二进制操作码编码和解码实现是否特定于websockets?

gul*_*uly 0 websocket socket.io

假设我正在创建一个websocket客户端.并且特定的websocket url将框架返回为"二进制框架(操作码2)".问题是

1.为什么开发人员想要将原始消息包装在二进制操作码框架内?
2.检索以实现为中心的消息吗?换句话说,客户端是否必须知道用于在服务器上编码的相同逻辑?
3.如果上述内容为false,那么是否存在解码/解析二进制操作码以查看正在发送的实际数据的全局方法?

Dav*_*ser 5

处理Websocket框架


Websocket框架基本上如下所示:

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 ...                |
+---------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

说明


  1. FIN
    • FIN位告诉您这是否是您将收到的所有数据.大型Websocket消息可以分段(通过多个帧发送)
  2. RSV1-3
    • 这是保留位,可以在以后使用
  3. opcode
    • 这可用于确定您收到的帧类型
    • 可能的选择是
      • 0(继续)
      • 如果此框架是一部分,而不是碎片消息的第一部分
    • 1(文字)
      • 普通的UTF-8编码文本数据
    • 2(二进制)
      • 二进制数据
    • 8(关闭)
      • 这关闭了Websocket
    • 9(平)
      • 服务器ping客户端以检查客户端是否仍可访问
    • 10(乒乓球)
      • 客户端使用a PongPing数据进行响应以验证其可达性
  4. MASK
    • 第二个字节的最高有效位告诉您有效负载是否已被屏蔽.一个服务器不能掩盖任何帧!
  5. 有效载荷长度(这是事情变得复杂的地方)
    • 取第2个字节并读取除最高有效位之外的所有位
      • 字节数是125或更少,这是你的长度
      • 字节是126
        • 你的长度是字节3和4的uint16
      • 字节是127
        • 你的长度是字节3到8的uint64
  6. 掩盖关键
    • 仅在该MASK位置位时才存在
    • 接下来的4个字节是屏蔽密钥,该密钥用于解码有效负载
  7. 有效载荷
    • 如果该FIN位置位,则不是整个有效负载
    • 有效载荷可以解码为文本(UTF-8)或二进制(可以是任何数据)
    • 如果MASK设置了位,则需要屏蔽有效负载

解码Websocket框架的步骤


  1. 得到FIN一点
    • 得到第一个字节,&它与127,结果是你的FIN
  2. 得到OpCode(OpCode告诉你你有什么类型的框架)
    • 得到第一个字节,&它与15,结果是你的opcode
  3. 得到MASK一点
    • 获取第二个字节,&然后使用127,如果是127则获得屏蔽密钥
  4. 获取有效负载长度
    • 取第2个字节并读取除最高有效位之外的所有位
      • 字节长度为125或更短
      • 字节是126
        • 你的长度是字节3和4的uint16
      • 字节是127
        • 你的长度是字节3到8的uint64
  5. 获取屏蔽密钥
    • 接下来的4个字节是屏蔽密钥,该密钥用于解码有效负载
  6. 有效载荷
    • 有效负载长度很长,从屏蔽密钥开始
    • 如果MASK设置该位,则需要屏蔽有效负载
      • 要取消屏蔽有效负载,您只需要xor在索引计数模4上使用屏蔽键对每个字节进行操作

int count = 0; for (int i = dataIndex; i < totalLength; i++) { frameData[i] = (byte)(frameData[i] ^ key[count % 4]); count++; }

解释数据


  • 文本
    • 数据需要解释为UTF-8文本
  • 二进制
    • 需要根据您等待的数据来解释此数据,这可以通过在有效负载的起始处添加一个字节然后相应地解释它来实现.