服务器与客户端的实时通信
我们在做聊天室的时候,会需要用到实时通信,当服务端向客户端提前声明,发送的是流信息的时候,HTTP 协议可以允许服务器向客户端发送消息,因为一次性发送不完,需要连续不断的发送,客户端不会关闭连接,会一直等着服务器发送新的数据流。
服务端与客户端的实时通信,主要有以下三种解决方案:
轮询
前端可以在自己的页面进行轮询(定时)调用后端的接口,然后触发后端给前端返回消息,虽然可以解决前后端实时推送的数据问题,但是这样做并不是一个最优解,使用 WebSocket 和 SSE 更好一点。
WebSocket
WebSocket 是一个全双工通道,客户端可以给服务端发送消息,并且可以接收服务端的消息,服务端也可以给客户端发送消息,接收客户端的消息。
websocket 有很多特点:
- 建立在 TCP 协议之上,服务器端的实现比较容易
- 与 HTTP 协议有着良好的兼容性。默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是 ws(如果加密,则为 wss),服务器网址就是 URL。
像直播的聊天室都是 WebSocket 做的。我们在使用 WebSocket 的时候,可以使用 socket.io 这个库,会方便很多。在前端页面需要依靠 socket.io.js,node 要依靠的库。
用一个简单的 socket.io 的例子,实现一下精简版的互相通信。废话不多说,上代码:
server 端:
const Koa = require('koa');const app = new Koa();const server = require('http').Server(app.callback());const io = require('socket.io')(server);const port = 8081;server.listen(process.env.PORT || port, () => { console.log(`app run at : http://127.0.0.1:${port}`);});io.on('connection', socket => { console.log('初始化成功!下面可以用socket绑定事件和触发事件了'); socket.on('send', data => { console.log('客户端发送的内容:', data); socket.emit('getMsg', '我是返回的消息... ...'); }); setInterval(() => { socket.emit('getMsg', '我是初始化3s后的返回消息... ...'); }, 3000);});复制代码
client 端:
websocket示例 复制代码服务器响应的消息:
- 前端通过 socket.on('事件名', callback)监听到后端的触发
- 前端通过 socket.emit('事件名', '消息体')向后端发送消息
- 后端通过 socket.emit('事件名', '消息体')向前端发送消息
- 后端通过 socket.on('事件名', callback)接收前端发送来的消息
- 后端通过 socket.on('disconnect')监听退出事件
- 后端可以通过 socket.broadcast.emit('message', '消息内容')进行广播
SSE(Server-Sent Events)
SSE 相对于 WebSocket 来说,没有 WebSocket 那么强大,因为 WebSocket 是全双工通道,但是 SSE 是单向通道,只能服务器向浏览器发送信息。
但是 SSE 相对 WebSocket 来说,也有自己的优点:
- 轻量级,使用简单,没有 WebSocket 的协议那么复杂
- 默认断线重连,WebSocket 需要自己去实现
- SSE 一般用来发送文本,如果发送二进制数据,需要编码后传输,WebSocket 默认支持传送二进制数据
具体的代码示例可以参考