WebSocket 通信过程与实现

作者:wzhvictor来源:https://segmentfault.com/a/1190000014643900 
什么是 WebSocket ?
WebSocket 是一种标准协议,用于在客户端和服务端之间进行双向数据传输 。但它跟 HTTP 没什么关系,它是基于 TCP 的一种独立实现 。
以前客户端想知道服务端的处理进度,要不停地使用 Ajax 进行轮询,让浏览器隔个几秒就向服务器发一次请求,这对服务器压力较大 。另外一种轮询就是采用 long poll 的方式,这就跟打电话差不多,没收到消息就一直不挂电话,也就是说,客户端发起连接后,如果没消息,就一直不返回 Response 给客户端,连接阶段一直是阻塞的 。
而 WebSocket 解决了 HTTP 的这几个难题 。当服务器完成协议升级后( HTTP -> WebSocket ),服务端可以主动推送信息给客户端,解决了轮询造成的同步延迟问题 。由于 WebSocket 只需要一次 HTTP 握手,服务端就能一直与客户端保持通信,直到关闭连接,这样就解决了服务器需要反复解析 HTTP 协议,减少了资源的开销 。
 

WebSocket 通信过程与实现

文章插图
 
随着新标准的推进,WebSocket 已经比较成熟了,并且各个主流浏览器对 WebSocket 的支持情况比较好(不兼容低版本 IE,IE 10 以下),有空可以看看 。
 
WebSocket 通信过程与实现

文章插图
 
使用 WebSocket 的时候,前端使用是比较规范的,js 支持 ws 协议,感觉类似于一个轻度封装的 Socket 协议,只是以前需要自己维护 Socket 的连接,现在能够以比较标准的方法来进行 。
 
WebSocket 通信过程与实现

文章插图
 
 
下面我们就结合上图具体来聊一下 WebSocket 的通信过程 。
建立连接
客户端请求报文 Header
客户端请求报文:
GET / HTTP/1.1Upgrade: websocketConnection: UpgradeHost: example.comOrigin: http://example.comSec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==Sec-WebSocket-Version: 13与传统 HTTP 报文不同的地方:
Upgrade: websocketConnection: Upgrade这两行表示发起的是 WebSocket 协议 。
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==Sec-WebSocket-Version: 13Sec-WebSocket-Key 是由浏览器随机生成的,提供基本的防护,防止恶意或者无意的连接 。
Sec-WebSocket-Version 表示 WebSocket 的版本,最初 WebSocket 协议太多,不同厂商都有自己的协议版本,不过现在已经定下来了 。如果服务端不支持该版本,需要返回一个 Sec-WebSocket-Versionheader,里面包含服务端支持的版本号 。
创建 WebSocket 对象:
var ws = new websocket("ws://127.0.0.1:8001");ws 表示使用 WebSocket 协议,后面接地址及端口
完整的客户端代码:
WebSocket 通信过程与实现

文章插图
 
服务端响应报文 Header
首先我们来看看服务端的响应报文:
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat我们一行行来解释
  • 首先,101 状态码表示服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求;
  • 然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key;
  • 最后,Sec-WebSocket-Protocol 则是表示最终使用的协议 。
Sec-WebSocket-Accept 的计算方法:
  • 将 Sec-WebSocket-Key 跟 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接;
  • 通过 SHA1 计算出摘要,并转成 base64 字符串 。
注意:Sec-WebSocket-Key/Sec-WebSocket-Accept 的换算,只能带来基本的保障,但连接是否安全、数据是否安全、客户端 / 服务端是否合法的 ws 客户端、ws 服务端,其实并没有实际性的保证 。
创建主线程,用于实现接受 WebSocket 建立请求:
WebSocket 通信过程与实现

文章插图
 
进行通信
服务端解析 WebSocket 报文
Server 端接收到 Client 发来的报文需要进行解析
Client 包格式
 
WebSocket 通信过程与实现

文章插图
 
 
1、FIN: 占 1bit
0:不是消息的最后一个分片
1:是消息的最后一个分片
2、RSV1, RSV2, RSV3:各占 1bit
一般情况下全为 0 。当客户端、服务端协商采用 WebSocket 扩展时,这三个标志位可以非0,且值的含义由扩展进行定义 。如果出现非零的值,且并没有采用 WebSocket 扩展,连接出错 。


推荐阅读