C#WebSocket服务器帧解码不工作和消息未知操作码

时间:2017-02-02 00:56:32

标签: c# sockets google-chrome websocket

所以我在c#中开发一个Web Socket服务器有一个正确的Web Socket升级,而且我在接收帧的时候,我似乎错误地解码了这些帧,

处理从框架读取的代码

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

2 个答案:

答案 0 :(得分:2)

这篇文章是一个好的开始:https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers

具体来说,我认为你处理得不好the frame length

  
      
  1. 读取位9-15(包括)并将其解释为无符号   整数。如果它是125或更小,那么这是长度;你完成了。   如果是126,请转到步骤2.如果是127,请转到步骤3.
  2.   
  3. 读取下16位并将其解释为无符号整数。你已经完成了。

  4.   
  5. 读取下一个64位并将其解释为无符号整数   (最重要的位必须是0)。你已经完成了。

  6.   

我这里没有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

答案 1 :(得分:0)

这是因为目前Chrome和Chrome中部署的实施方案似乎存在问题。 Firefox由于某种原因\ r \ n没有结束Sec-WebSocket-Accept标题中的行,因此需要一个空格,因此在浏览器中关于标题上的\r\n的实现有问题

"HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "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"
            )
        )
   ) + " \r\n\r\n";