使用 Socket.io 库制作一个简单的实时聊天室

WebSocket 介绍
传统的 http,在客户端没发送请求给服务器之前是不会有响应的,客户端发送请求后服务器才作出响应,明显是单向的,如果要持续获取资源就得不断重复请求

后来就有了长轮询(Long polling)的方法,客户端让 HTTP 请求保持一段时间,即使没有数据的时候也得保持连接。再后来,就有了 WebSocket
WebSocket 是专门设计来做实时应用的协议,WebSocket 和 HTTP 很像,WebSocket 请求的 URL 用的是 ws 或者 wss,在 HTTP 协议里对应 HTTP 和 HTPPS
客户端如果要发起 WebSocket 请求,需要在请求首部里作出说明,Connection 的值写成 Upgrade,Upgrade 的值写成 WebSocket,服务器收到请求后会看到连接要求升级,升级成什么在 Upgrade 里找,于是服务器就知道客户端要建立 WebSocket 连接,建立连接后就可以传输数据了

WebSocket 建立连接
我们用 node.js 来生成服务器,首先npm init -y
初始化,然后安装 Websocket 依赖npm i ws
,创建一个server.js
作为服务器文件

在 service 里引入安装的模块,生成一个 WebSocket 实例并指名使用的端口
加入事件操作,有人连接进来的时候使用connection
来指明这个状态,并用 wx 参数表示不同的单一连接,有人退出的话要在单一连接中进行,也就是使用 wx 参数指明close
状态的时候
测试一下,但是现在直接用浏览器访问服务器是没有效果的,因为浏览器是使用 HTTP 访问的,不会告诉服务器用 WebSocket 连接,所以还需要创建一个 index.html 文件,在 html 文件里面成一个 WebSocket 实例,参数里填写 URL,因为是在开发所以直接使用 ws,实例应用中一般是 wss,是安全版的 ws
node server.js 运行服务器,然后运行 index.html,打开页面前端和后端的控制台都有提示了,关闭页面也会有提示,也就是断开连接,WebSocket 的连接功能也就实现了



不过还缺少了数据传输功能,还是在单一连接里进行操作,如果收到 message 就把客户端的信息处理一下返回给客户端。客户端也需要设置在连接上就马上发送信息给服务器并监听 message 事件,有数据就在控制台输出返回的数据
刷新页面,可以看到控制台打印的消息无误就代表实现了数据传输

Socket.io 库
Socket.io 库也有用到 WebSocket 协议,但是对不支持 WebSocket 的浏览器会回退到 HTTP 轮询,还提供自动重连,是一个更高级的库,有了 WebSocket 的基础就可以使用 Socket.io 实现一个简单的实时聊天应用
还是和上面操作大致一样,初始化,npm i express socket.io
安装 express 和 socket.io 依赖,创建 server.js 和 index.html
先用安装好的 express 库生成一个实例 app 再调用 http 模块,并使用 app 实例生成一个服务器实例,也就是基于 http 模块生成服务器实例,写起来更方便一些
当接收到请求的时候,把 html 文件作为响应的文件
html 代码,主要有 input 输入框和按钮,聊天内容就放在 ul 标签里


注意服务器不能直接用 app.listen,不然还是使用 HTTP 进行交互,使用刚刚创建的 server 实例创建一个 socket.io 实例,使用 service 实例监听端口
和之前 WebSocket 连接操作很类似,有人连接进来的时候使用connection
来指明这个状态并用 socket 参数表示不同的单一连接,有人退出的话要在单一连接中进行,也就是使用 socket 参数指明disconnect
状态的时候
客户端也要作出相应的连接,和刚刚 WebSocket 不同的是,因为这是服务器响应文件,可以直接在 script 标签里指定路径,这样可以调用到 io 函数
运行服务器,在浏览器里访问 localhost:3000,可以看到服务器控制台有提示,代表连接成功了,关掉浏览器页面服务器也有提示,代表断开连接了

连接成功就可以来实现实时消息的功能了,服务端在 socket 连接的时候开启chat message
事件,客户端先获取 form 和 input 两个元素,并且监听 form 的有提交动作的时候,先取消防止默认刷新事件,输入框有内容的时候触发 chat message 事件传入输入框的内容,然后清空一下输入框
重启一下服务器,在浏览器里访问 localhost:3000,在输入框里输入值点击发送按钮触发chat message
事件将值传给服务器


服务器收到后还得广播给所有人,这样才能更新聊天室的内容,在chat message
事件下用 io 这个实例触发一下 chat message,并且把从客户端收到的数据发送出去
客户端获取一下 ul 元素,使用 socket 实例监听chat message
事件,服务器发来数据就生成新的 li 元素,把数据内容放进 li 元素里面,然后使用 appendChild 为 ul 新增子元素 li
服务器重启之后打开多个页面输入消息,其他页面也会有同步的消息,也就实现了实时聊天室了

版权声明: 本文为 InfoQ 作者【格斗家不爱在外太空沉思】的原创文章。
原文链接:【http://xie.infoq.cn/article/26ad755bcb923cdbcbf1e1f69】。文章转载请联系作者。
评论