JavaScript

超轻量级php框架startmvc

Nodejs实现多房间简易聊天室功能

更新时间:2020-05-18 21:54:01 作者:startmvc
1、前端界面代码  前端不是重点,够用就行,下面是前端界面,具体代码可到github下载

1、前端界面代码

  前端不是重点,够用就行,下面是前端界面,具体代码可到github下载。

2、服务器端搭建

  本服务器需要提供两个功能:http服务和websocket服务,由于node的事件驱动机制,可将两种服务搭建在同一个端口下。

  1、包描述文件:package.json,这里用到了两个依赖项,mime:确定静态文件mime类型,socket.io:搭建websocket服务,然后使用npm install  安装依赖


{
 "name": "chat_room",
 "version": "1.0.0",
 "description": "this is a room where you can chat with your friends",
 "main": "index.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "sfs",
 "license": "ISC",
 "dependencies": {
 "socket.io":"2.0.3",
 "mime":"1.3.6"
 }
}

  2、http服务器

  http服务主要是给web浏览器提供静态文件,既浏览器发来一个请求,服务器返回一个响应。


const 
 http=require('http'),
 fs=require('fs'),
 path=require('path'),
 mime=require('mime'),
 chatServer=require('./lib/chat_server');

var cache={};//缓存静态文件内容
//发送错误响应
function send404(response){
 response.writeHead(404,{'Content-Type':'text/plain'});
 response.write('Error 4.4:文件未找到。');
 response.end();
}
//发送文件内容
function sendFile(response,filePath,fileContents){
 response.writeHead(
 200,
 {"content-Type":mime.lookup(path.basename(filePath))}
 );
 response.end(fileContents);
}
//查找文件
function serveStatic(response,cache,absPath){
 if(cache[absPath]){
 sendFile(response,absPath,cache[absPath]);
 }else{
 fs.exists(absPath,function(exists){
 if(exists){
 fs.readFile(absPath,function(err,data){
 if(err){
 send404(response);
 }else{
 cache[absPath]=data;
 sendFile(response,absPath,data);
 }
 });
 }else{
 send404(response);
 }
 });
 }
}
//入口
var server=http.createServer(function(request,response){
 var filePath=false;
 console.log(`new request for ${request.url}`);
 if(request.url==='/'){
 filePath='public/index.html';
 }else{
 filePath='public'+request.url;
 }

 var absPath='./'+filePath;
 serveStatic(response,cache,absPath);
});
server.listen(3000,function(){
 console.log("the server is listening on prot 3000.");
});
chatServer.listen(server); //websocket服务也绑定到该端口上

  3、socket服务

  socket.io提供了开箱既用的虚拟通道,所以不需要任务手动转发消息到已连接的的用户,可以使用 socket.broadcast.to(room).emit('message','hello'); room为某个聊天室id


const 
 socketio=require('socket.io');
var io,
 guestNumber=1, //用户编号
 nickNames={}, //socket id对应的nickname
 namesUsed={}, //所有已使用的nickname
 allRooms={}, //聊天室--人数
 currentRoom={}; //sockid--聊天室
module.exports.listen=function(server){
 io=socketio.listen(server);
 io.serveClient('log level',1);
 io.sockets.on('connection',function(socket){
 guestNumber=assignGuestName(socket,guestNumber,nickNames);
 joinRoom(socket,'Lobby');
 handleMessageBroadcasting(socket,nickNames);
 handleNameChangeAttempts(socket,nickNames,namesUsed);
 handleRoomJoining(socket);
 socket.on('rooms',function(){
 socket.emit('rooms',JSON.stringify(allRooms));
 });
 handleClientDisconnection(socket,nickNames,namesUsed);
 });
};
//新socket连入,自动分配一个昵称
function assignGuestName(socket,guesetNumber,nickNames){
 var name='Guest'+guestNumber;
 nickNames[socket.id]=name;
 socket.emit('nameResult',{
 success:true,
 name:name
 });
 namesUsed[name]=1;
 return guestNumber+1;
}
//加入某个聊天室
function joinRoom(socket,room){
 socket.join(room);
 var num=allRooms[room];
 if(num===undefined){
 allRooms[room]=1;
 }else{
 allRooms[room]=num+1;
 }
 currentRoom[socket.id]=room;
 socket.emit('joinResult',{room:room});
 socket.broadcast.to(room).emit('message',{
 text:nickNames[socket.id]+' has join '+room+'.'
 });
 var usersinRoom=io.sockets.adapter.rooms[room];
 if(usersinRoom.length>1){
 var usersInRoomSummary='Users currently in '+room+' : ';
 for(var index in usersinRoom.sockets){
 if(index!=socket.id){
 usersInRoomSummary+=nickNames[index]+',';
 }
 }
 socket.emit('message',{text:usersInRoomSummary}); 
 }
}
//修改昵称
function handleNameChangeAttempts(socket,nickNames,namesUsed){
 socket.on('nameAttempt',function(name){
 if(name.indexOf('Guest')==0){
 socket.emit('nameResult',{
 success:false,
 message:'Names cannot begin with "Guest".'
 });
 }else{
 if(namesUsed[name]==undefined){
 var previousName=nickNames[socket.id];
 delete namesUsed[previousName];
 namesUsed[name]=1;
 nickNames[socket.id]=name;
 socket.emit('nameResult',{
 success:true,
 name:name
 });
 socket.broadcast.to(currentRoom[socket.id]).emit('message',{
 text:previousName+' is now known as '+name+'.'
 });
 }else{
 socket.emit('nameResult',{
 success:false,
 message:'That name is already in use.' 
 });
 }
 }
 }); 
}
//将某个用户的消息广播到同聊天室下的其他用户
function handleMessageBroadcasting(socket){
 socket.on('message',function(message){
 console.log('message:---'+JSON.stringify(message));
 socket.broadcast.to(message.room).emit('message',{
 text:nickNames[socket.id]+ ': '+message.text
 });
 });
}
//加入/创建某个聊天室
function handleRoomJoining(socket){
 socket.on('join',function(room){
 var temp=currentRoom[socket.id];
 delete currentRoom[socket.id];
 socket.leave(temp);
 var num=--allRooms[temp];
 if(num==0)
 delete allRooms[temp];
 joinRoom(socket,room.newRoom);
 });
}
//socket断线处理
function handleClientDisconnection(socket){
 socket.on('disconnect',function(){
 console.log("xxxx disconnect");
 allRooms[currentRoom[socket.id]]--;
 delete namesUsed[nickNames[socket.id]];
 delete nickNames[socket.id];
 delete currentRoom[socket.id];
 })
}

3、客户端实现socket.io

  1、chat.js处理发送消息,变更房间,聊天命令。


var Chat=function(socket){
 this.socket=socket;//绑定socket
}
//发送消息
Chat.prototype.sendMessage=function(room,text){
 var message={
 room:room,
 text:text
 };
 this.socket.emit('message',message);
};
//变更房间
Chat.prototype.changeRoom=function(room){
 this.socket.emit('join',{
 newRoom:room
 });
};
//处理聊天命令
Chat.prototype.processCommand=function(command){
 var words=command.split(' ');
 var command=words[0].substring(1,words[0].length).toLowerCase();
 var message=false;
 switch(command){
 case 'join':
 words.shift();
 var room=words.join(' ');
 this.changeRoom(room);
 break;
 case 'nick':
 words.shift();
 var name=words.join(' ');
 this.socket.emit('nameAttempt',name);
 break;
 default:
 message='Unrecognized command.';
 break;
 }
 return message;
};

  2、chat_ui.js 处理用户输入,根据输入调用chat.js的不同方法发送消息给服务器


function divEscapedContentElement(message){
 return $('<div></div>').text(message);
}
function divSystemContentElement(message){
 return $('<div></div>').html('<i>'+message+'</i>');
}
function processUserInput(chatApp,socket){
 var message=$('#send-message').val();
 var systemMessage;
 if(message.charAt(0)=='/'){
 systemMessage=chatApp.processCommand(message);
 if(systemMessage){
 $('#messages').append(divSystemContentElement(systemMessage));
 }
 }else{
 chatApp.sendMessage($('#room').text(),message);
 $('#messages').append(divSystemContentElement(message));
 $('#messages').scrollTop($('#messages').prop('scrollHeight'));
 }
 $('#send-message').val('');
}

  3、init.js客户端程序初始化   创建一个websocket连接,绑定事件。


if(window.WebSocket){
 console.log('This browser supports WebSocket');
}else{
 console.log('This browser does not supports WebSocket');
}
var socket=io.connect();
$(document).ready(function(){
 var chatApp=new Chat(socket);
 socket.on('nameResult',function(result){
 var message;
 if(result.success){
 message='You are known as '+result.name+'.';
 }else{
 message=result.message;
 }
 console.log("nameResult:---"+message);
 $('#messages').append(divSystemContentElement(message));
 $('#nickName').text(result.name);
 });
 socket.on('joinResult',function(result){
 console.log('joinResult:---'+result);
 $('#room').text(result.room);
 $('#messages').append(divSystemContentElement('Room changed.'));
 });
 socket.on('message',function(message){
 console.log('message:---'+message);
 var newElement=$('<div></div>').text(message.text);
 $('#messages').append(newElement);
 $('#messages').scrollTop($('#messages').prop('scrollHeight'));
 });
 socket.on('rooms',function(rooms){
 console.log('rooms:---'+rooms);
 rooms=JSON.parse(rooms);
 $('#room-list').empty();
 for(var room in rooms){
 $('#room-list').append(divEscapedContentElement(room+':'+rooms[room]));
 }
 $('#room-list div').click(function(){
 chatApp.processCommand('/join '+$(this).text().split(':')[0]);
 $('#send-message').focus();
 });
 });
 setInterval(function(){
 socket.emit('rooms');
 },1000);
 $('#send-message').focus();
 $('#send-button').click(function(){
 processUserInput(chatApp,socket);
 });
});

完整代码,可到https://github.com/FleyX/ChatRoom 下载。

以上所述是小编给大家介绍的Nodejs实现多房间简易聊天室功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

nodejs 聊天室 nodejs 多房间