# 实时通信方案 - [WebSockets](https://developer.mozilla.org/zh-CN/docs/Web/API/WebSockets_API) - [Server-sent Event(SSE)](https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events) - 长链接(服务器端轮询) - 短链接(客户端轮询) > [网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket (baidu.com)](https://baijiahao.baidu.com/s?id=1700709358061982511&wfr=spider&for=pc) > [Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE (taodudu.cc)](http://www.taodudu.cc/news/show-614593.html?action=onClick) > [详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket (360doc.com)](http://www.360doc.com/content/22/0525/15/32573_1033094047.shtml) ## 建设介绍 1. 采用工具 后端:ws ^8.13.0 前端:socket.io ^4.7.2 2. demo操作 ```bash # 启动server npm i npm run start:server # 启动客户端 cd client npm i npm run start:client # 进入页面输入昵称和ServerIP即可开始聊天 ``` ## WebSocket > WebSocket是客户端和服务器之间的可以双向通信的全双工通信协议。 1. 特点 (1)建立在 TCP 协议之上,服务器端的实现比较容易。(建立通信时采用http协议) (2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。 (3)数据格式比较轻量,性能开销小,通信高效。 (4)可以发送文本,也可以发送二进制数据(blob对象或Arraybuffer对象) (5)收到的数据类型 可以使用binaryType 指定, 显式指定收到的二进制数据类型 (6)没有同源限制,客户端可以与任意服务器通信。 (7)协议标识符是ws(握手http)(如果加密,则为wss(tcp +TLS)),服务器网址就是 URL。 2. 使用 ```js const socket = new WebSocket(`ws://hostname:port/path`); socket.onopen = event => { // 当socket与服务器练级成功时触发 } socket.onerror = event =>{ // 当socket出现错误时触发,包括网络错误,断开连接,服务器错误等 console.error('Error',event) } socket.onclose = event => { // 当socket断开连接时触发 // WebSocket没有断线重连机制,如需重连,在此方法内编写重连逻辑 } ws.onmessage = event => { const msg = event.data // 当接收到服务器发送的消息时触发 ws.send('消息内容');// 这里可以选择二进制数据发送 } ``` ## SSE > SSE的本质其实就是一个HTTP的长连接,只不过它给客户端发送的不是一次性的数据包,而是一个stream流,格式为text/event-stream。所以客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。 1. 特点 1)SSE 使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议。 2)SSE 属于轻量级,使用简单;WebSocket 协议相对复杂。 3)SSE 默认支持断线重连,WebSocket 需要自己实现。 4)SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据。 5)SSE 支持自定义发送的消息类型。 2. 缺点 1)客户端无法发送消息,需要通过接口单独请求 3. 使用 ```js const eventSource = new EventSource('/api/system/msg/connect?id=' + userId, { headers: { 'Content-Type': 'text/event-stream', 'Authorization': 'token' } }); eventSource.addEventListener("open", function (e) { console.log('open successfully') }) /* * message:后端返回信息,格式可以和后端协商 */ eventSource.addEventListener("message", function (e) { console.log(e.data) }) /* * error:错误 */ eventSource.addEventListener("error", function (err) { // console.log(err) // 类似的返回信息验证,这里是实例 err && err.status === 401 && console.log('not authorized') }) ``` ## 长链接 > 客户端和服务端建立连接后不进行断开,之后客户端再次访问这个服务器上的内容时,继续使用这一条连接通道。 ## 短链接 > 客户端和服务端建立连接,发送完数据后立马断开连接。下次要取数据,需要再次建立连接。 > > Http长连接和TCP长连接的区别在于: TCP 的长连接需要自己去维护一套心跳策略。而Http只需要在请求头加入keep-alive:true即可实现长连接。 ## Socket.IO > Socket.IO 是一个库,可以在客户端和服务器之间实现低延迟, 双向和基于事件的通信。 1. 特点 1)它建立在 WebSocket 协议之上,并提供额外的保证,如果无法建立WebSocket连接,连接将回退到HTTP长轮询或自动重新连接。 2)自动重新连接 3)数据包缓冲。当客户端断开连接时,数据包会自动缓冲,并在重新连接时发送。 ```js import { io } from "https://cdn.socket.io/4.3.2/socket.io.esm.min.js"; const socket = io("http://127.0.0.1:3000") socket.on("connect", () => { //监听连接是否成功 console.log("链接成功"); }); socket.on("disconnect", (reason) => { //监听连接异常中断 console.log("中断", reason); }); socket.on("message_event", (data) => { // "message_event"时后端定义的发送字段 console.log("接收到的消息", data); }) // 前端主动断开链接 socket.close() socket.disconnect() socket.on('connect',() => { // 与服务器连接成功 console.log('socket链接成功!'+socket.id) }) // 其他事件 // connect:连接成功 // connecting:正在连接 // disconnect:断开连接 // connect_failed:连接失败 // error:错误发生,并且无法被其他事件类型所处理 // reconnect_failed:重连失败 // reconnect:成功重连 // reconnecting:正在重连 ```