websocket 建立过程以及数据帧分析

websocket 建立过程

客户端请求

  • Connection: Upgrade 表示要升级协议
  • Upgrade: websocket 告诉服务器要升级为 websocket 协议
  • Sec-WebSocket-Version: 13 表示 websocket 的版本。如果服务端不支持该版本,需要返回一个Sec-WebSocket-Versionheader,里面包含服务端支持的版本号。
  • Sec-WebSocket-Key:客户端随机生成的一个base64编码,与后面服务端响应头配套,提供基本的防护,防止无意的连接。
GET /chat HTTP/1.1     
Host: server.example.com     
Upgrade: websocket     
Connection: Upgrade     
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==     
Sec-WebSocket-Protocol: chat, superchat     
Sec-WebSocket-Version: 13     
Origin: http://example.com

服务器响应

  • 服务器返回 101 状态码,并切换为 WebSocket 协议建立全双工连接
  • Sec-WebSocket-Accept:客户端请求头的 Sec-Websocket-Key 与 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 拼接,通过 SHA1 算摘要,最后转为 base64 字符串返回。

所谓防止无意的连接是指,http 客户端不小心请求了 websocket 服务。

HTTP/1.1 101 
Switching Protocols     
Upgrade: websocket     
Connection: Upgrade     
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=     
Sec-WebSocket-Protocol: chat

数据帧分析

图来自掘金-黄Java-【译】WebSocket协议第五章——数据帧(Data Framing)

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

FIN: 1 bit。表示这是消息的最后一个片段。第一个片段也有可能是最后一个片段。

RSV1,RSV2,RSV3: 每个1 bit。必须设置为0,除非扩展了非0值含义的扩展。如果收到了一个非0值但是没有扩展任何非0值的含义,接收终端必须断开WebSocket连接。

Opcode: 4 bit。操作码,如果收到一个未知的操作码,接收终端必须断开WebSocket连接。

  • %x0 表示一个持续帧
  • %x1 表示一个文本帧
  • %x2 表示一个二进制帧
  • %x3-7 预留给以后的非控制帧
  • %x8 表示一个连接关闭包
  • %x9 表示一个ping包
  • %xA 表示一个pong包
  • %xB-F 预留给以后的控制帧

Mask: 1 bit,mask标志位,定义“有效负载数据”是否添加掩码。如果设置为1,那么掩码的键值存在于Masking-Key中。Masking-Key中一般用于解码“有效负载数据”。

Payload length: 7 bits, 7+16 bits, or 7+64 bits,以字节为单位的“有效负载数据”长度。如果值为0-125,那么就表示负载数据的长度。如果是126,那么接下来的2个bytes解释为16bit的无符号整形作为负载数据的长度。如果是127,那么接下来的8个bytes解释为一个64bit的无符号整形(最高位的bit必须为0)作为负载数据的长度。多字节长度量以网络字节顺序表示(译注:应该是指大端序和小端序)。在所有的示例中,长度值必须使用最小字节数来进行编码,例如:长度为124字节的字符串不可用使用序列126,0,124进行编码。有效负载长度是指“扩展数据”+“应用数据”的长度。“扩展数据”的长度可能为0,那么有效负载长度就是“应用数据”的长度。

Masking-Key: 0 or 4 bytes,所有从客户端发往服务端的数据帧都已经与一个包含在这一帧中的32 bit的掩码进行过了运算。为什么需要掩码?为了安全,但并不是为了防止数据泄密,而是为了防止早期版本的协议中存在的代理缓存污染攻击(proxy cache poisoning attacks)等问题。

Payload data:有效负载数据,是指“扩展数据”和“应用数据”。

Extension data: x bytes:除非协商过扩展,否则“扩展数据”长度为0 bytes。

Application data: y bytes。任意的“应用数据”,占用“扩展数据”后面的剩余所有字段。“应用数据”的长度等于有效负载长度减去“扩展应用”长度。

参考

即时通信网-Web端即时通讯技术盘点

掘金-黄Java-Websocket 协议 RFC 文档(全中文翻译)

原来你是这样的 websocket

posted @ 2020-06-03 11:23  Ever-Lose  阅读(1300)  评论(0编辑  收藏  举报