如何在WebSockets hybi 08+中构造数据帧



自从Chrome升级到v14,他们从草案的第三版到草案的第八版。

我有一个在WebSocket上运行的内部聊天应用程序,虽然我已经得到了新的握手工作,数据帧显然也发生了变化。我的WebSocket服务器是基于nuget的。

有没有人有WebSocket工作与版本8的草案,并有一个例子,如何框架的数据正在通过电线发送?

(参见:如何在服务器端发送和接收WebSocket消息?)


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

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

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

第二个字节包含一个1(这意味着它被"屏蔽"了)。(编码)),后面是7位,表示帧大小。如果在000 0000111 1101之间,这就是大小。如果它是111 1110,下面的2个字节是长度(因为它不适合7位),如果它是111 1111,下面的8个字节是长度(如果它也不适合2个字节)。

后面是四个字节,它们是"mask "你需要解码帧数据。这是使用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
});

你也可以下载对你有帮助的规范(它当然包含了所有你需要理解的格式)

这个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);
    }

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

帧已经从使用'x00…xff'使用一个2-7字节的报头的每一帧,其中包含的有效载荷的长度等事项。在规范的第4.2节中有一个框架格式的示意图。还要注意,从客户端(浏览器)到服务器的数据是屏蔽的(4个字节的客户端-服务器帧报头包含解密密钥)。

你可以看看websockify,它是一个WebSockets到TCP套接字代理/桥接,我创建了它来支持noVNC。它是用python实现的,但你应该能够从encode_hybi和decode_hybi例程中获得思想。

相关内容

  • 没有找到相关文章

最新更新