• 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"
      }
    }
    View Code

      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服务也绑定到该端口上
    View Code

      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 }
    View Code

    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:room
    16     });
    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 }; 
    View Code

      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 }
    View Code

      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 });
    View Code

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

      

  • 相关阅读:
    宋体freetype16和12号字无法正常显示
    Visual Studio 2015 自动生成 的大文件xxx.vc.db的删除问题
    PP助手上传失效
    freetype教程网址
    编译器发展
    静态与动态库文件
    makefile文件操作大全
    Unicode编码字符范围和具体文字
    Oracle用户被锁定解决方法
    oracle中rownum和row_number()
  • 原文地址:https://www.cnblogs.com/wuyoucao/p/7052841.html
Copyright © 2020-2023  润新知