如何(de)在WebSockets hybi 08+中构建数据框架?

gis*_*rad 8 c# websocket

自从Chrome更新到第14 版后,他们从草案的第3版升级到草稿第8版.

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

有没有人让WebSocket使用草案的第8版,并举例说明如何构建通过线路发送的数据?

pim*_*vdb 16

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


这很容易,但理解格式很重要.

第一个字节几乎总是1000 0001,其中1意味着"最后一帧",三个0s是保留位,到目前为止没有任何意义,这0001意味着它是一个文本框架(Chrome随ws.send()方法发送).

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

第二个字节包含a 1(意味着它被"屏蔽"(编码)),后面跟着表示帧大小的7位.如果它在000 0000和之间111 1101,那就是大小.如果是111 1110,则后面的2个字节是长度(因为它不适合7位),如果是111 1111,则后面的8个字节是长度(如果它也不适合两个字节).

接下来是四个字节,它们是解码帧数据所需的"掩码".这是使用xor编码完成的,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
});
Run Code Online (Sandbox Code Playgroud)

您也可以下载有用的规范(当然它包含了解格式所需的一切).


小智 12

这个c#代码对我来说很好.通过套接字解码从浏览器到ac#server的文本数据.

    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);
    }
Run Code Online (Sandbox Code Playgroud)