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

时间:2016-12-13 07:43:24

标签: websocket socket.io

假设我正在创建一个websocket客户端。并且特定的websocket url将框架返回为“二进制框架(操作码2)”。问题是:1。为什么开发人员想要将原始消息包装在二进制操作码框架内?
2.检索以消息实现为中心吗?换句话说,客户端是否必须知道用于在服务器上编码的相同逻辑?
3.如果上述内容为假,那么是否存在解码/解析二进制操作码以查看正在发送的实际数据的全局方法?

1 个答案:

答案 0 :(得分: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 ...                |
+---------------------------------------------------------------+

解释

  1. FIN
    • FIN位告诉您这是否是您将收到的所有数据。大型Websocket消息可以分段(通过多个帧发送)
  2. RSV1-3
    • 这是保留位,稍后可以使用
  3. opcode
    • 这可用于确定您收到的框架类型
    • 可能的选择是
      • 0(继续)
      • 如果此框架是一部分,而不是碎片消息的第一部分
    • 1(文字)
      • 普通UTF-8编码文本数据
    • 2(二进制)
      • 二进制数据
    • 8(关闭)
      • 关闭了Websocket
    • 9(Ping)
      • 服务器ping客户端以检查客户端是否仍可访问
    • 10(乒乓球)
      • 客户回复PongPing数据以验证其可达性
  4. MASK
    • 第二个字节的最高有效位,告诉您有效负载是否已被屏蔽。 服务器不得屏蔽任何帧!
  5. 有效载荷长度(这是事情变得复杂的地方)
    • 取第2个字节并读取除最高有效位以外的所有位
      • 字节数为125或更少
      • 字节是126
        • 您的长度是字节3和4的uint16
      • 字节是127
        • 您的长度是字节3到8的uint64
  6. 屏蔽键
    • 仅在MASK位设置
    • 时才存在
    • 接下来的4个字节是屏蔽密钥,此密钥用于解码有效负载
  7. 有效载荷
    • 如果设置FIN
    • ,则不是整个有效负载
    • 有效载荷可以解码为文本(UTF-8)或二进制(可以是任何数据)
    • 如果设置了MASK
    • ,则需要屏蔽有效负载
  8. 解码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位,则需要屏蔽有效负载
        • 要屏蔽有效负载,只需要在索引计数模4上使用屏蔽键对每个字节进行xor操作
    7. int count = 0; for (int i = dataIndex; i < totalLength; i++) { frameData[i] = (byte)(frameData[i] ^ key[count % 4]); count++; }

      解释数据

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