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: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 }; 

  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 下载。

  

时间: 2024-10-25 19:38:26

nodejs构建多房间简易聊天室的相关文章

socket.io入门,简易聊天室

介绍 通常我们web使用的是http协议,但是 HTTP 协议有一个缺陷:通信只能由客户端发起. 所以我们需要一个可以由服务端主动发出的协议,即WebSocket. WebSocket是HTML5新增的一种通信协议,其特点是服务端可以主动向客户端推送信息,客户端也可以主动向服务端发送信息,是真正的双向平等对话,属于服务器推送技术的一种. Socket.IO 是一个基于 Node.js 的实时应用程序框架,在即时通讯.通知与消息推送,实时分析等场景中有较为广泛的应用. socket.io 包含两个

php+websocket搭建简易聊天室实践

1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短连接和长连接.短连接一般可以用ajax实现,长连接就是websocket.短连接实现起来比较简单,但是太过于消耗资源.websocket高效不过兼容存在点问题.websocket是html5的资源 如果想要详细了解websocket长连接的原理请看https://www.zhihu.com/ques

php_3_“简易聊天室 ”实现的关键技术 详解

                  PHP+MySQL实现Internet上一个简易聊天室的关键技术  系统目标: 聊天室使用数据库汇集每个人的发言,并可将数据库内的发言信息显示在页面,让每个用户都可以看到,具体功能如下: a.用户登录:用户发言时显示其登录名信息 b.用户发言:用户输入说的话 c.显示发言信息:用户浏览所有发言信息 设计思路: (1).建立聊天室数据库及相关数据表 (2).实现用户登录页面(login.php) (3).实现发言页面(speak.php) (4).实现发言显示页

Socket编程(简易聊天室客户端/服务器编写、CocoaAsyncSocket)

Socket编程(简易聊天室客户端/服务器编写.CocoaAsyncSocket) 一.Socket 1.1 Socket简介 Socket就是为网络服务提供的一种机制.网络通信其实就是Socket间的通信,通信的两端都是Socket,数据在两个Socket间通过IO传输. 在Web服务大行其道的今天,调用Web服务的代价是高昂的,尤其是仅仅是抓取少量数据的时候尤其如此.而使用Socket,可以只传送数据本身而不用进行XML封装,大大降低数据传输的开销.Socket允许使用长连接,允许应用程序运

使用nodejs+express+socketio+mysql搭建聊天室

使用nodejs+express+socketio+mysql搭建聊天室 nodejs相关的资料已经很多了,我也是学习中吧,于是把socket的教程看了下,学着做了个聊天室,然后加入简单的操作mysql数据库存聊天记录.express主要是做了路由及jade模板.我是用的国外的免费空间托管的,国内各种备案,它的访问地址是:nodejs聊天室http://chat.lovewebgames.com/,效果图如下: 用到的插件如下: "socket.io":"~1.3.5&quo

docker搭建swoole简易聊天室

docker搭建swoole的简易聊天室 首先pull镜像 docker pull docker.io/kong36088/nginx-php7-swoole 创建容器 docker run --name {自己创建的名字} -p 9501:9501 -p 8089:80 -d -it kong36088/nginx-php7-swoole /bin/bash 进入容器 docker exec -it {容器名字或id} /bin/bash 进入容器之后进入nginx配置文件 cd /etc/n

基于C/S模式的简易聊天室

一.任务简要描述 移动互联网技术的广泛应用为人们提供了非常便捷的沟通方式.QQ.微信和微博等是便携式聊天系统的典型代表,它们的功能非常强大. 本系统利用TCP/IP协议的Socket和ServerSocket类,实现基于C/S模式的简易聊天室.该聊天室包括服务端和客户端两部分,服务端是客户端发送消息的中转站:客户端之间可以直接通信,也可以与服务器通信.聊天结束后客户端断开与服务端的连接,服务器也可以停止信息中转服务. 二.系统需求分析 本系统采用C/S软件架构,服务器端负责监听客户端发来的消息,

[Redis]-Redis简易聊天室

代码来自图书<左手MongoDB,右手Redis>第六章-简易聊天室 1.下载代码 2.安装部署py运行环境 yum install python3 -y yum install python-virtualenv -y pip install pipenv pip install --upgrade pip 3.运行代码 cd /RedisChat/ pipenv install export FLASK_APP=main.py flask run -h 10.0.0.51 -p 5000

nodejs多房间web聊天室

一年之前的做的小项目,过了许久,翻出当时的PPT文档总结一下.源码下载:https://github.com/CreekLou/chatRoom Nodejs背景简介 1 ,JavaScript最早是运行在浏览器中,然而浏览器只是提供了一个上下文 2 ,node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码 3 ,Node.js事实上既是一个运行时环境,同时又是一个库 Nodejs架构如下图 Node.js 的异步机制是基于事件的,所有的磁盘 I/O