首页 > 编程 > JavaScript > 正文

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

2019-11-19 16:18:03
字体:
来源:转载
供稿:网友

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实现多房间简易聊天室功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表