【问题标题】:How to (de)construct data frames in WebSockets hybi 08+?如何在 WebSockets hybi 08+ 中(反)构造数据帧?
【发布时间】:2011-10-25 18:53:26
【问题描述】:

自从 Chrome 更新到 v14 后,它们从 version three of the draft 变为 version eight of the draft

我有一个在 WebSocket 上运行的内部聊天应用程序,虽然我已经让新的握手工作正常了,但数据框架显然也发生了变化。我的 WebSocket 服务器基于Nugget

是否有人让 WebSocket 与草案的第八版一起使用,并且有一个关于如何构建通过网络发送的数据的示例?

【问题讨论】:

    标签: c# websocket


    【解决方案1】:

    (另见:How can I send and receive WebSocket messages on the server side?


    这很简单,但理解格式很重要。

    第一个字节几乎总是1000 0001,其中1 表示“最后一帧”,三个0s 是保留位,到目前为止没有任何意义,0001 表示它是一个文本帧( Chrome 使用ws.send() 方法发送)。

    (更新:Chrome 现在还可以发送带有ArrayBuffer 的二进制帧。第一个字节的最后四位将是0002,因此您可以区分文本和二进制数据。数据解码的工作方式完全相同。)

    第二个字节包含1(意味着它被“屏蔽”(编码))后跟代表帧大小的七位。如果它在000 0000111 1101 之间,那就是大小。如果是111 1110,后面的2个字节是长度(因为它放不下7位),如果是111 1111,后面的8个字节是长度(如果它也放不下两个字节) )。

    接下来是四个字节,它们是解码帧数据所需的“掩码”。这是使用 xor 编码完成的,该编码使用数据的indexOfByteInData mod 4 定义的掩码之一。解码就像encodedByte xor maskByte 一样工作(其中maskByteindexOfByteInData mod 4)。

    现在我必须说我根本没有使用 C# 的经验,但这是一些伪代码(恐怕是一些 JavaScript 口音):

    var length_code = bytes[1] & 127, // remove the first 1 by doing '& 127'
        masks,
        data;
    
    if(length_code === 126) {
        masks = bytes.slice(4, 8);   // 'slice' returns part of the byte array
        data  = bytes.slice(8);      // and accepts 'start' (inclusively)
    } else if(length_code === 127) { // and 'end' (exclusively) as arguments
        masks = bytes.slice(10, 14); // Passing no 'end' makes 'end' the length
        data  = bytes.slice(14);     // of the array
    } else {
        masks = bytes.slice(2, 6);
        data  = bytes.slice(6);
    }
    
    // 'map' replaces each element in the array as per a specified function
    // (each element will be replaced with what is returned by the function)
    // The passed function accepts the value and index of the element as its
    // arguments
    var decoded = data.map(function(byte, index) { // index === 0 for the first byte
        return byte ^ masks[ index % 4 ];          // of 'data', not of 'bytes'
        //         xor            mod
    });
    

    您也可以下载the specification,这会很有帮助(它当然包含您理解格式所需的所有内容)。

    【讨论】:

    • 甜...我会在星期一的工作中尝试一下。如果成功,我会给你接受的答案...... :)
    • 终于开始为我的 websocket 服务器查看这个解决方案。工作就像一个魅力......谢谢,伙计......
    • @Gísli Konráð:这对你来说太棒了; WebSockets 对调试并不友好。
    • 我认为您的代码在我测试系统时不完整我从客户端 websocket 获取此字节并且无法解码此字节:136,128,44,185,105,136 秒字节为 128,您的代码不支持?跨度>
    【解决方案2】:

    这个 c# 代码对我来说很好用。将来自浏览器的文本数据通过套接字解码到 c# 服务器。

        public static string GetDecodedData(byte[] buffer, int length)
        {
            byte b = buffer[1];
            int dataLength = 0;
            int totalLength = 0;
            int keyIndex = 0;
    
            if (b - 128 <= 125)
            {
                dataLength = b - 128;
                keyIndex = 2;
                totalLength = dataLength + 6;
            }
    
            if (b - 128 == 126)
            {
                dataLength = BitConverter.ToInt16(new byte[] { buffer[3], buffer[2] }, 0);
                keyIndex = 4;
                totalLength = dataLength + 8;
            }
    
            if (b - 128 == 127)
            {
                dataLength = (int)BitConverter.ToInt64(new byte[] { buffer[9], buffer[8], buffer[7], buffer[6], buffer[5], buffer[4], buffer[3], buffer[2] }, 0);
                keyIndex = 10;
                totalLength = dataLength + 14;
            }
    
            if (totalLength > length)
                throw new Exception("The buffer length is small than the data length");
    
            byte[] key = new byte[] { buffer[keyIndex], buffer[keyIndex + 1], buffer[keyIndex + 2], buffer[keyIndex + 3] };
    
            int dataIndex = keyIndex + 4;
            int count = 0;
            for (int i = dataIndex; i < totalLength; i++)
            {
                buffer[i] = (byte)(buffer[i] ^ key[count % 4]);
                count++;
            }
    
            return Encoding.ASCII.GetString(buffer, dataIndex, dataLength);
        }
    

    【讨论】:

    • 这应该标记为答案,根据问题(C#代码)
    • 什么是totalLength,为什么要在其中添加keyIndex + 4
    【解决方案3】:

    更准确地说,Chrome 已经从协议的Hixie-76 版本升级为协议的HyBi-10 版本。 HyBi-08 到 HyBi-10 都报告为版本 8,因为它实际上只是更改了规范文本,而不是电汇格式。

    帧已从使用 '\x00...\xff' 更改为对每个帧使用 2-7 字节的标头,其中包含有效负载的长度等。规范的section 4.2 中有帧格式图。另请注意,从客户端(浏览器)到服务器的数据被屏蔽(客户端-服务器帧头的 4 个字节包含取消屏蔽键)。

    您可以查看websockify,它是我创建的用于支持noVNC 的WebSockets 到TCP 套接字代理/桥接器。它是在 python 中实现的,但您应该能够从 encode_hybidecode_hybi 例程中得到这个想法。

    【讨论】:

      猜你喜欢
      • 2011-12-30
      • 1970-01-01
      • 1970-01-01
      • 2020-11-07
      • 2014-11-06
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      相关资源
      最近更新 更多