自从Chrome升级到v14,他们从草案的第三版到草案的第八版。
我有一个在WebSocket上运行的内部聊天应用程序,虽然我已经得到了新的握手工作,数据帧显然也发生了变化。我的WebSocket服务器是基于nuget的。
有没有人有WebSocket工作与版本8的草案,并有一个例子,如何框架的数据正在通过电线发送?
(参见:如何在服务器端发送和接收WebSocket消息?)
这很简单,但是理解格式很重要。
第一个字节几乎总是1000 0001
,其中1
表示"最后一帧",三个0
是迄今为止没有任何意义的保留位,0001
表示它是一个文本帧(Chrome使用ws.send()
方法发送)。
(更新: Chrome现在也可以发送二进制帧与ArrayBuffer
。第一个字节的最后四位将是0002
,因此您可以区分文本和二进制数据。数据的解码工作方式完全相同)
第二个字节包含一个1
(这意味着它被"屏蔽"了)。(编码)),后面是7位,表示帧大小。如果在000 0000
和111 1101
之间,这就是大小。如果它是111 1110
,下面的2个字节是长度(因为它不适合7位),如果它是111 1111
,下面的8个字节是长度(如果它也不适合2个字节)。
后面是四个字节,它们是"mask "你需要解码帧数据。这是使用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#代码对我来说工作得很好。解码通过套接字从浏览器发送到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例程中获得思想。