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

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==='https://www.jb51.net/'){ 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+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处理发送消息,变更房间,聊天命令。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyxydx.html