首页 > 代码库 > nodejs构建多房间简易聊天室
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浏览器提供静态文件,既浏览器发来一个请求,服务器返回一个响应。
1 const 2 http=require(‘http‘), 3 fs=require(‘fs‘), 4 path=require(‘path‘), 5 mime=require(‘mime‘), 6 chatServer=require(‘./lib/chat_server‘); 7 8 var cache={};//缓存静态文件内容 9 //发送错误响应10 function send404(response){11 response.writeHead(404,{‘Content-Type‘:‘text/plain‘});12 response.write(‘Error 4.4:文件未找到。‘);13 response.end();14 }15 //发送文件内容16 function sendFile(response,filePath,fileContents){17 response.writeHead(18 200,19 {"content-Type":mime.lookup(path.basename(filePath))}20 );21 response.end(fileContents);22 }23 //查找文件24 function serveStatic(response,cache,absPath){25 if(cache[absPath]){26 sendFile(response,absPath,cache[absPath]);27 }else{28 fs.exists(absPath,function(exists){29 if(exists){30 fs.readFile(absPath,function(err,data){31 if(err){32 send404(response);33 }else{34 cache[absPath]=data;35 sendFile(response,absPath,data);36 }37 });38 }else{39 send404(response);40 }41 });42 }43 }44 45 46 //入口47 var server=http.createServer(function(request,response){48 var filePath=false;49 console.log(`new request for ${request.url}`);50 if(request.url===‘/‘){51 filePath=‘public/index.html‘;52 }else{53 filePath=‘public‘+request.url;54 }55 56 var absPath=‘./‘+filePath;57 serveStatic(response,cache,absPath);58 });59 server.listen(3000,function(){60 console.log("the server is listening on prot 3000.");61 });62 chatServer.listen(server); //websocket服务也绑定到该端口上
3、socket服务
socket.io提供了开箱既用的虚拟通道,所以不需要任务手动转发消息到已连接的的用户,可以使用 socket.broadcast.to(room).emit(‘message‘,‘hello‘); room为某个聊天室id
1 const 2 socketio=require(‘socket.io‘); 3 4 var io, 5 guestNumber=1, //用户编号 6 nickNames={}, //socket id对应的nickname 7 namesUsed={}, //所有已使用的nickname 8 allRooms={}, //聊天室--人数 9 currentRoom={}; //sockid--聊天室 10 11 module.exports.listen=function(server){ 12 io=socketio.listen(server); 13 io.serveClient(‘log level‘,1); 14 io.sockets.on(‘connection‘,function(socket){ 15 guestNumber=assignGuestName(socket,guestNumber,nickNames); 16 joinRoom(socket,‘Lobby‘); 17 handleMessageBroadcasting(socket,nickNames); 18 handleNameChangeAttempts(socket,nickNames,namesUsed); 19 handleRoomJoining(socket); 20 socket.on(‘rooms‘,function(){ 21 socket.emit(‘rooms‘,JSON.stringify(allRooms)); 22 }); 23 handleClientDisconnection(socket,nickNames,namesUsed); 24 }); 25 }; 26 //新socket连入,自动分配一个昵称 27 function assignGuestName(socket,guesetNumber,nickNames){ 28 var name=‘Guest‘+guestNumber; 29 nickNames[socket.id]=name; 30 socket.emit(‘nameResult‘,{ 31 success:true, 32 name:name 33 }); 34 namesUsed[name]=1; 35 return guestNumber+1; 36 } 37 //加入某个聊天室 38 function joinRoom(socket,room){ 39 socket.join(room); 40 var num=allRooms[room]; 41 if(num===undefined){ 42 allRooms[room]=1; 43 }else{ 44 allRooms[room]=num+1; 45 } 46 currentRoom[socket.id]=room; 47 socket.emit(‘joinResult‘,{room:room}); 48 socket.broadcast.to(room).emit(‘message‘,{ 49 text:nickNames[socket.id]+‘ has join ‘+room+‘.‘ 50 }); 51 52 var usersinRoom=io.sockets.adapter.rooms[room]; 53 if(usersinRoom.length>1){ 54 var usersInRoomSummary=‘Users currently in ‘+room+‘ : ‘; 55 for(var index in usersinRoom.sockets){ 56 if(index!=socket.id){ 57 usersInRoomSummary+=nickNames[index]+‘,‘; 58 } 59 } 60 socket.emit(‘message‘,{text:usersInRoomSummary}); 61 } 62 } 63 //修改昵称 64 function handleNameChangeAttempts(socket,nickNames,namesUsed){ 65 socket.on(‘nameAttempt‘,function(name){ 66 if(name.indexOf(‘Guest‘)==0){ 67 socket.emit(‘nameResult‘,{ 68 success:false, 69 message:‘Names cannot begin with "Guest".‘ 70 }); 71 }else{ 72 if(namesUsed[name]==undefined){ 73 var previousName=nickNames[socket.id]; 74 delete namesUsed[previousName]; 75 namesUsed[name]=1; 76 nickNames[socket.id]=name; 77 socket.emit(‘nameResult‘,{ 78 success:true, 79 name:name 80 }); 81 socket.broadcast.to(currentRoom[socket.id]).emit(‘message‘,{ 82 text:previousName+‘ is now known as ‘+name+‘.‘ 83 }); 84 }else{ 85 socket.emit(‘nameResult‘,{ 86 success:false, 87 message:‘That name is already in use.‘ 88 }); 89 } 90 } 91 }); 92 } 93 //将某个用户的消息广播到同聊天室下的其他用户 94 function handleMessageBroadcasting(socket){ 95 socket.on(‘message‘,function(message){ 96 console.log(‘message:---‘+JSON.stringify(message)); 97 socket.broadcast.to(message.room).emit(‘message‘,{ 98 text:nickNames[socket.id]+ ‘: ‘+message.text 99 });100 });101 }102 //加入/创建某个聊天室103 function handleRoomJoining(socket){104 socket.on(‘join‘,function(room){105 var temp=currentRoom[socket.id];106 delete currentRoom[socket.id];107 socket.leave(temp);108 var num=--allRooms[temp];109 if(num==0)110 delete allRooms[temp];111 joinRoom(socket,room.newRoom);112 });113 }114 //socket断线处理115 function handleClientDisconnection(socket){116 socket.on(‘disconnect‘,function(){117 console.log("xxxx disconnect");118 allRooms[currentRoom[socket.id]]--;119 delete namesUsed[nickNames[socket.id]];120 delete nickNames[socket.id];121 delete currentRoom[socket.id];122 })123 }
3、客户端实现socket.io
1、chat.js处理发送消息,变更房间,聊天命令。
1 var Chat=function(socket){ 2 this.socket=socket;//绑定socket 3 } 4 //发送消息 5 Chat.prototype.sendMessage=function(room,text){ 6 var message={ 7 room:room, 8 text:text 9 };10 this.socket.emit(‘message‘,message);11 };12 //变更房间13 Chat.prototype.changeRoom=function(room){14 this.socket.emit(‘join‘,{15 newRoom:room16 });17 };18 //处理聊天命令19 Chat.prototype.processCommand=function(command){20 var words=command.split(‘ ‘);21 var command=words[0].substring(1,words[0].length).toLowerCase();22 var message=false;23 24 switch(command){25 case ‘join‘:26 words.shift();27 var room=words.join(‘ ‘);28 this.changeRoom(room);29 break;30 case ‘nick‘:31 words.shift();32 var name=words.join(‘ ‘);33 this.socket.emit(‘nameAttempt‘,name);34 break;35 default:36 message=‘Unrecognized command.‘;37 break;38 }39 return message;40 };
2、chat_ui.js 处理用户输入,根据输入调用chat.js的不同方法发送消息给服务器
1 function divEscapedContentElement(message){ 2 return $(‘<div></div>‘).text(message); 3 } 4 function divSystemContentElement(message){ 5 return $(‘<div></div>‘).html(‘<i>‘+message+‘</i>‘); 6 } 7 function processUserInput(chatApp,socket){ 8 var message=$(‘#send-message‘).val(); 9 var systemMessage;10 if(message.charAt(0)==‘/‘){11 systemMessage=chatApp.processCommand(message);12 if(systemMessage){13 $(‘#messages‘).append(divSystemContentElement(systemMessage));14 }15 }else{16 chatApp.sendMessage($(‘#room‘).text(),message);17 $(‘#messages‘).append(divSystemContentElement(message));18 $(‘#messages‘).scrollTop($(‘#messages‘).prop(‘scrollHeight‘));19 }20 $(‘#send-message‘).val(‘‘);21 }
3、init.js客户端程序初始化 创建一个websocket连接,绑定事件。
1 if(window.WebSocket){ 2 console.log(‘This browser supports WebSocket‘); 3 }else{ 4 console.log(‘This browser does not supports WebSocket‘); 5 } 6 var socket=io.connect(); 7 $(document).ready(function(){ 8 var chatApp=new Chat(socket); 9 socket.on(‘nameResult‘,function(result){10 var message;11 if(result.success){12 message=‘You are known as ‘+result.name+‘.‘;13 }else{14 message=result.message;15 }16 console.log("nameResult:---"+message);17 $(‘#messages‘).append(divSystemContentElement(message));18 $(‘#nickName‘).text(result.name);19 });20 21 socket.on(‘joinResult‘,function(result){22 console.log(‘joinResult:---‘+result);23 $(‘#room‘).text(result.room);24 $(‘#messages‘).append(divSystemContentElement(‘Room changed.‘));25 });26 27 socket.on(‘message‘,function(message){28 console.log(‘message:---‘+message);29 var newElement=$(‘<div></div>‘).text(message.text);30 $(‘#messages‘).append(newElement);31 $(‘#messages‘).scrollTop($(‘#messages‘).prop(‘scrollHeight‘));32 });33 34 socket.on(‘rooms‘,function(rooms){35 console.log(‘rooms:---‘+rooms);36 rooms=JSON.parse(rooms);37 $(‘#room-list‘).empty();38 for(var room in rooms){39 $(‘#room-list‘).append(divEscapedContentElement(room+‘:‘+rooms[room]));40 }41 $(‘#room-list div‘).click(function(){42 chatApp.processCommand(‘/join ‘+$(this).text().split(‘:‘)[0]);43 $(‘#send-message‘).focus();44 });45 });46 47 setInterval(function(){48 socket.emit(‘rooms‘);49 },1000);50 51 $(‘#send-message‘).focus();52 $(‘#send-button‘).click(function(){53 processUserInput(chatApp,socket);54 });55 });
完整代码,可到https://github.com/FleyX/ChatRoom 下载。
nodejs构建多房间简易聊天室
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。