使用node.js + socket.io 构建多个房间聊天室
安装node以及相关插件
node我已经安装了,就不重复操作了,还有不会安装node的同学,请自行百度;
现在我们先创建一个package.json的问件,这里我们可以利用node自动生成:
> npm init
现在我们目录下回自动生成一个package.json文件
接下来安装我们需要的socket.io , 这里我选择的是0.9.6的版本,因为1.0版本有些API有所改变;
npm install socket.io@0.9.6 --save
后面的 –save 是指将信息添加到package.json文件中:
现在安装好了socket.io , 接下来我们安装mime , mime模块是用来获取文件类型,以便设置正确的HTTP头的 “Content-Type”
> npm install mime@1.2.7 --save
接下来看看我们的目录和package.json文件:
现在多了一个node_modules文件夹,里面放着我们所需要的模块,还有package.json文件里面,也多了mime 和 socket.io ,这说明我们已经成功安装了;接下来说一下我们的目录结构:
创建静态文件服务器
现在我们想搭建一个静态文件服务器,先在sever.js里面添加以下代码:
现在我们创建了一个HTTP服务器,并监听3000端口,3000是我随便选的,其他的也可以,只要没有被占用;接下来我们写以下提供静态文件的serceStatic方法:
现在我们的HTTP服务器就已经搭建起来了,接下来我们运行看一下:
> node server
打开浏览器 地址栏输入localhost:3000
这个时候我们看到页面上显示一个错误信息 “Error 404: resource not found.”,不用担心,这个时候我们服务器正常已经跑起来了,只是我们现在还没有添加静态文件,接下来我们在public目录下,添加一下我们的静态文件;
先在public目录下添加我们想要的文件,并引入需要的css和js
添加一下CSS样式
现在重新刷新一下页面,应该是下面这样:
到目前为止,我们的初期准备工作都已完成,接下来就是搭建我们的socket服务器了
使用socket.io搭建聊天室服务器
首先,我们先在lib目录下创建一个chat_server.js的文件,我们的socket.io服务器内容将写在这个里面;
第一步,我们先在server.js文件里面,引入我们的chat_server.js ,并将socket.io服务器与我们的HTTP服务器共享同一个端口号;
接下来我们开始编写我们的chat_server.js ;
现在我们初始化了一些变量,并且我们创建了一个事件监听,当有用户连接时,会调用一个自动分配访客名的assignGuestName函数;
接下来我们来写一下这个函数;
在这里我们做了四件事:
1、生成了一个系统的默认昵称;
2、将昵称和socket ID 关联起来;
3、将昵称广播给用户;
4、将昵称保存起来,以便别人修改昵称的时候不会重名。
现在我们在客户端添加代码,给socket.io绑定一个“nameResult”事件监听,编写我们的chat_ui.js文件:
接下来重启一下服务器,刷新页面,现在应该看到的是这个样子,现在页面显示了我们系统自动分配的用户名:
现在我们可以看到,页面已经显示出来了系统给我们的昵称,细心的同学可能会发现,控制台提示了一堆bug,像这样:
第一个其实是版本问题,我们先不用管他,后面的那些debug 都是一些授权之类的提示,这里我们不深究里面的内容,不想看到的同学,也可以关闭socket.io的debug信息功能,只需要在chat_server.js里面加上一句代码就行:
这里我们是将信息直接放到了页面#messages的元素里面,这里我们要将信息处理一下,如果用户输入script标签,直接放入页面这样容易形成跨域脚本攻击(XSS)攻击,这里我们写两个函数方法,用来处理用户输入信息和系统信息;
并且判断一下用户名有没有问题,有问题直接在聊天窗口显示出来;
接下来我们将用户放入聊天室里面,这里我们默认放在“Lobby”聊天室里面,编写我们的chat_server.js
这里我们的joinRoom()要做一下几件事情:
1、让用户进入房间;
2、记录用户当前的房间;
3、让用户知道他们进入了新房间;
4、让房间其他用户知道有新用户进入房间;
5、将房间里的其他用户汇总发送给这个用户;
现在我们再客户端监听一下joinResult()事件和message()事件;
现在再来看看我们的页面效果,现在我们可以看到一些基本信息了,现在页面显示我们已经进入到了lobby聊天室
我们再来开一个窗口看看,这个时候应该会给Guest1提示Guest2进入房间,并且告诉Guest2有谁在Lobby房间;
接下来我们编写发送消息
在客户端chat_ui.js也加入发送消息的逻辑:
现在我们让Guest1用户发送一条消息,看看Guest2能不能接收到:
现在我们可以看到,Guest2收到了Guest1发送的消息,但是Guest1现在没有任何反应,因为我们是将message事件广播给除自己之外的所有用户的,所以我们要做一下处理,因为后续还有修改昵称和更换房间的命令,这里我们将聊天信息封装一下,这样让代码看起来比较优雅:
这里我们封装了一个Chat对象,并且将它实例化了,接下来我们看看Chat里面的逻辑代码,开始编写我们的chat.js
这里我们创建了一个Chat的构造函数,并且在它原型上创建了一个sendMessage的方法专门来发送聊天消息;
接下来,我们回过头来编写我们的chat_ui.js里面的processUserInput()方法,这个函数专门用来处理input里面的输入内容;
现在Guest1输入消息的时候,自己聊天窗口也会显示自己输入的消息:
到现在为止,我们的聊天室基本就已经完成了,现在我们再将功能完善一下,让用户可以修改昵称和更换房间;
先在我们服务器端添加一下更名请求的处理程序:
客户端chat_ui.js添加用户输入判断逻辑:
同样,我们再Chat原型上添加对应的processCommand()方法:
重启服务器,在页面输入修改昵称的命令:
同时输入错误的指令会报错,重复的昵称也会有提示:
接下来,我们添加更换房间的指令,同样的现在服务器端添加创建房间的逻辑代码:
接下来,我们再客户端天剑添加处理更换房间指令的逻辑代码:
现在我们再浏览器上试试:
现在我们可以看到,我们通过“/join aaa”的指令,成功的切换到了aaa的房间:
细心的同学可能会发现一个问题,那就是现在到底有哪些聊天室存在?
这里我们获取一下存在的聊天室,并显示出来,同时还添加一个事件,点击聊天室列表里面的名称,直接可以更换到该聊天室;
char_server.js
char_ui.js
现在再看看我们的页面,更换下房间试试:
记得要开两个以上的窗口看效果,因为我们的程序会自动清除没有人的房间,所以如果只有一个用户,那永远都只能看到一个房间;
最后我们再将功能完善一下,当用户离开的时候,自动释放昵称,以便其他用户使用;
至此,我们的聊天室就已经全部完成,代码比较简陋,主要是实现基本功能,还有很多地方可以去优化和完善;
再次提醒下,我这里用的socket.io是0.9.6版本的,如果有同学用的是1+版本的,记得里面有些API有所改变,
io.sockets.clients(room) 可以换成 io.sockets.adapter.rooms[room]
io.sockets.manager.rooms 可以换成 io.sockets.adapter.rooms
不过亲测数据有点改变,需要有小的改动,这里就不列出来了,大家可以去试试。