如何(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 0000
和111 1101
,那就是大小。 如果它是111 1110
,则后面的2个字节是长度(因为它不适合7位),如果它是111 1111
,则后面的8个字节是长度(如果它也不适合两个字节)。
接下来是四个字节,它们是解码帧数据所需的“掩码”。 这是使用xor编码完成的,xor编码使用数据的indexOfByteInData mod 4
定义的掩码之一。 解码只是像encodedByte xor maskByte
(其中maskByte
是indexOfByteInData 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例程中获得想法。