Nodejs实现多房间简易聊天室功能
程序员文章站
2022-03-21 14:57:25
1、前端界面代码
前端不是重点,够用就行,下面是前端界面,具体代码可到github下载。
2、服务器端搭建
本服务器需要提供两个功能:http服务和webso...
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实现多房间简易聊天室功能,希望对大家有所帮助
上一篇: 微信小程序实现皮肤功能(夜间模式)