所以我在 c# 中开发 Web 套接字服务器时,Web 套接字正确升级,并且我正在接收帧,但我似乎解码了不正确的帧,
用于处理从帧读取的代码
bool started = false;
// to write something back.
while (bClientConnected)
{
try
{
msg = this.decryptFrame(client.Client);
Console.WriteLine("Client Frame Decrypt: " + msg);
//sWriter.WriteLine("pong!");
//sWriter.Flush();
}
catch (Exception)
{
Console.WriteLine("Connection from " + ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString() + " was terminated unkown reason.");
bClientConnected = false;
client.Close();
continue;
}
started = true;
}
用于解析和调试帧的代码:
public string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
private string decryptFrame(Socket sock)
{
// busy wait untill something is sent
while (sock.Available == 0) { }
var header = new byte[6];
sock.Receive(header);
var length = header[1] & 127;
Console.WriteLine("Recived header >> " + this.ByteArrayToString(header));
var body = new byte[length];
sock.Receive(body);
Console.WriteLine("Recived body >> " + this.ByteArrayToString(body));
for (var i = 0; i < length; i++)
{
body[i] ^= header[2 + (i & 3)];
}
Console.WriteLine("decoded body >> " + this.ByteArrayToString(body));
string resp = Encoding.UTF8.GetString(body, 0, length);
Console.WriteLine("Parsed body >> " + resp);
return resp;
}
问题是chrome帧立即在帧视图中显示(Opcode -1)
,并且发送到我的服务器的唯一帧被调试为
Recived header >> 88909495d0d4
Recived body >> 977f85bafffbbfa3fab5bfa4f7fab4b1
decoded body >> 03ea556e6b6e6f776e206f70636f6465
Parsed body >> ?Unknown opcode
Client Frame Decrypt: ?Unknown opcode
本文是一个良好的开端: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers
具体来说,我认为您没有很好地处理帧长度。
- 读取第 9-15 位(含)并将其解释为无符号 整数。如果是 125 或更小,那么这就是长度;大功告成。 如果是 126,请转到步骤 2。如果是 127,请转到步骤 3。
读取接下来的 16 位并将其解释为无符号整数。大功告成。
读取接下来的 64 位并将其解释为无符号整数 (最高有效位必须为 0)。大功告成。
我这里没有 VS,但这里有一个怪癖的例子:
var buffer = new byte[8192];
// put a frame in the buffer
// I am assuming that the frame is complete, starting at byte 0.
// Usually you will have to deal with incomplete frames
FillBuffer(buffer);
// length is in the second byte
int length = buffer[1];
// in the second byte, the first bit enables or disables MASK
// this bit would add a value of +128 (2^7) if enabled
length = (value >= 128 ? value - 128:value);
if(length == 126) // medium size frame
length = BitConverter.ToUint16(frame, 2);
else if(length == 127) // big ass frame
length = BitConverter.ToUint64(frame, 2);
else if(length > 127)
throw new InvalidOperationException($"Invalid frame length {length}");
我用 C# 开发了一个 WebSocket 组件,如果你有疑问,你可能会发现代码很有趣: https://github.com/vtortola/WebSocketListener
这是由于某种原因,当前部署在Chrome和Firefox中的实现似乎存在问题,\r没有结束Sec-WebSocket-Accept
标头中的行,因此需要一个空格,因此浏览器中的实现在标头上的rn
方面存在问题
"HTTP/1.1 101 Switching Protocolsrn"
+ "Connection: Upgradern"
+ "Upgrade: websocketrn"
+ "Sec-WebSocket-Accept: " + Convert.ToBase64String(
SHA1.Create().ComputeHash(
Encoding.UTF8.GetBytes(
new Regex("Sec-WebSocket-Key: (.*)").Match(headerBlock).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
)
)
) + " rnrn";