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

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

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

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

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


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

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

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

第二个字节包含1 (意味着它被“屏蔽”(编码)),后面跟着表示帧大小的7位。 如果它在000 0000111 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 }); 

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

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

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

框架已经从使用’\ x00 … \ xff’变为使用2-7字节标头,每个框架包含有效负载的长度等。 在规范的4.2节中有一个帧格式图。 另请注意,从客户端(浏览器)到服务器的数据被屏蔽(客户端 – 服务器帧头的4个字节包含取消屏蔽密钥)。

您可以查看websockify ,它是我为支持noVNC而创建的TCP套接字代理/网桥的WebSockets。 它是在python中实现的,但你应该能够从encode_hybi和decode_hybi例程中获得想法。