Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
奇怪的数据包从Chrome websocket客户端到达C#websocket服务器_C#_Google Chrome_Websocket - Fatal编程技术网

奇怪的数据包从Chrome websocket客户端到达C#websocket服务器

奇怪的数据包从Chrome websocket客户端到达C#websocket服务器,c#,google-chrome,websocket,C#,Google Chrome,Websocket,我有一个C#服务器端websocket代码,我正在从Chrome(javascript websocket客户端)发送测试数据 下面是:,以及其他一些链接,我创建了我的C#webserver(服务器端)解码函数,如下所示: public String DecodeMessage(Byte[] bytes) { Console.WriteLine("+DecodeMessage+"); String incomingData = String.Empty; Byte sec

我有一个C#服务器端websocket代码,我正在从Chrome(javascript websocket客户端)发送测试数据

下面是:,以及其他一些链接,我创建了我的C#webserver(服务器端)解码函数,如下所示:

public String DecodeMessage(Byte[] bytes)
{
    Console.WriteLine("+DecodeMessage+");
    String incomingData = String.Empty;
    Byte secondByte = bytes[1];
    bool masked = (bytes[1] & 128) != 0;
    //long dataLength = secondByte & 127;
    dataLength = secondByte & 127;
    //Int32 indexFirstMask = 2;
    indexFirstMask = 2;
    if (masked)
    {
        Console.WriteLine("Masked bit SET");
    }
    if (dataLength == 126)
    {
        indexFirstMask = 4;
        dataLength = bytes[3] | bytes[2] << 8;
    }
    else if (dataLength == 127)
    {
        indexFirstMask = 10;
        dataLength = bytes[9] | bytes[8] << 8 | bytes[7] << 16 | bytes[6] << 24 | bytes[5] << 32 |
            bytes[4] << 40 | bytes[3] << 48 | bytes[2] << 56;
    }

    //IEnumerable<Byte> keys = bytes.Skip(indexFirstMask).Take(4);
    keys = bytes.Skip(indexFirstMask).Take(4);
    Int32 indexFirstDataByte = indexFirstMask + 4;

    Byte[] decoded = new Byte[bytes.Length - indexFirstDataByte];
    Console.WriteLine("dataLength : " + dataLength + " ; bytes.Length : " + bytes.Length);
    Int32 j = 0;
    for (Int32 i = indexFirstDataByte; i < bytes.Length; i++)
    {
        decoded[j] = (Byte)(bytes[i] ^ keys.ElementAt(j % 4));
        j++;
    }
    Console.WriteLine("-DecodeMessage-");

    return incomingData = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
}
public String DecodeRemainingMessage(Byte[] bytes, long bytesAlreadyRead)
{
    Console.WriteLine("+DecodeRemainingMessage+");
    String incomingData = String.Empty;

    Int32 indexFirstDataByte = 0;
    if ( indexFirstMask == 10 )//special case, what to do here?
    {
        indexFirstDataByte = 10;
    }

    Byte[] decoded = new Byte[bytes.Length - indexFirstDataByte];
    //Byte[] decoded = new Byte[bytes.Length];
    Int32 j = 0;
    for (Int32 i = indexFirstDataByte; i < bytes.Length; i++)
    {
        decoded[j] = (Byte)(bytes[i] ^ keys.ElementAt(j % 4));
        j++;
    }
    Console.WriteLine("-DecodeRemainingMessage-");

    return incomingData = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
}
这两个条件都不满足,数据长度始终小于126,然后将其解码为(小)数据包,因此无法正确重建

谁能强调一下我可能做错了什么

谢谢

[*]=>长度低于65535的数据有时会包含两个以上的数据包,其行为方式与较大的数据包相同,并且在第一次命中此函数后,数据包再也无法正确重建

编辑1: @马克

根据您的评论,我在上面的函数中加入了“掩码位检查”,我可以看到它总是设置为“1”(正如预期的那样,因为这是目前唯一的服务器端代码)

我还在另一个函数中解析控制帧,在这个函数中,如果我的代码正确,我可能会得到很多垃圾数据

如需详细说明,请参见以下功能:

整个逻辑代码:

枚举:

public enum ControlFrame { NA=0, CloseConnection=1, Ping=2, Pong=4, Text=8, Binary=16, ContinueFrame =32, FinalFrame=64 };
解析控制帧函数:

private int ParseControlFrame(byte controlFrame)
{
    int rv = (int)ControlFrame.NA;
    bool isFinalFrame = (controlFrame & 0x80) == 0x80 ;
    byte opCode = (byte)((controlFrame & 0x0F));
    if ( opCode >= 0x3 && opCode <= 0x7    ||
        opCode >= 0xB && opCode <= 0xF    )//special frame, ignore it
    {
        Console.WriteLine("Reserved Frame received");
        return rv;
    }
    if (opCode == 0x8 || opCode == 0x0 || opCode == 0x1 || opCode == 0x2 || opCode == 0x9 || opCode == 0xA) //proceed furter
    {
        if (opCode == 0x0) //continue frame
        {
            rv |= (int)ControlFrame.ContinueFrame;
            Console.WriteLine("Continue Frame received");
        }
        if (opCode == 0x1) //text frame
        {
            rv |= (int)ControlFrame.Text;
            Console.WriteLine("Text Frame received");
        }
        if (opCode == 0x2) //binary frame
        {
            rv |= (int)ControlFrame.Binary;
            Console.WriteLine("Binary frame received");
        }
        if (opCode == 0x8) //connection closed
        {
            rv |= (int)ControlFrame.CloseConnection;
            Console.WriteLine("CloseConnection Frame received");
        } 
        if (opCode == 0x9) //ping
        {
            rv |= (int)ControlFrame.Ping;
            Console.WriteLine("PING received");
        }
        if (opCode == 0xA) //pong
        {
            rv |= (int)ControlFrame.Pong;
            Console.WriteLine("PONG received");
        }
    }
    else // invalid control bit, must close the connection
    {
        Console.WriteLine("invalid control frame received, must close connection");
        rv = (int)ControlFrame.CloseConnection;
    }
    if (isFinalFrame) //Final frame ...
    {
        rv |= (int)ControlFrame.FinalFrame;
        Console.WriteLine("Final frame received");
    }
    //else
    //{
    //    rv |= (int)ControlFrame.ContinueFrame;
    //    Console.WriteLine("Continue frame received");
    //}
    return rv;
}
我没有垃圾,但数据丢失了

如果我不付支票,我就开始收垃圾

根据Console.WriteLine输出,我发现小于65535的数据也有类似的情况:

Message received on: 12/29/2017 12:59:00 PM
Text Frame received
Final frame received
Masked bit SET
Message received on: 12/29/2017 12:59:12 PM
Text Frame received
Final frame received
Masked bit SET
对于65535以上的数据:

Message received on: 12/29/2017 1:02:51 PM
Text Frame received
Final frame received
Masked bit SET
Message received on: 12/29/2017 1:02:51 PM
Reserved Frame received
i、 e.少于65535,我还行(大部分时间)

在65535以上,情况变得很奇怪

当你提到:

I wonder if what is happening is that you're getting multiple messages in a single Read call (perfectly normal in TCP), consuming the first message, and incorrectly treating the entire bytes as consumed.
我以前从没想过,也许我也需要处理一下

编辑2:

根据您的评论,我修改了“if(stream.DataAvailable)”逻辑,因此它会继续读取while循环中的数据,直到本地存储的所有数据都被清除

因此,我可能即将解决它(感谢您的反馈),但是第二次调用DecodeMessage()函数时,它仍然会在垃圾(二进制)数据中解密

我正在努力想办法

谢谢

编辑3:

好的,根据你的建议,我已经把大部分逻辑整理好了。然而,“DecodeRemainingMessage”函数中的特殊情况仍然是个谜。[我将一些变量从局部范围转移到类范围,因此它们在函数中被注释掉]

如果我答对了,我不需要在这里放置任何特殊条件,但在这种情况下,我仍然会收到垃圾

有什么建议吗

[很抱歉代码太乱,我得到正确的图片后会更新它!]

谢谢

编辑4:
根据您在评论/聊天中的建议,我对解码逻辑进行了极大的更新,但在超过65535字节的情况下,仍然无法获得正确的数据。但当我尝试Firefox的最终逻辑时,我正确地获得了所有数据!非常感谢你们,而且,我仍然需要弄清楚如何处理有bug的Chrome客户端!谢谢

编辑:您的代码假定传入帧总是被屏蔽的。如果您的代码只是一个服务器,那么这可能是正常的,但您可能需要检查
字节[1]&128
是否已设置(屏蔽)或清除(未屏蔽)。如果未屏蔽:标头将短4个字节。如果这只是一个服务器,您应该可以,如(RFC6455中的5.2):

从客户端发送到服务器的所有帧都将此位设置为1

但是:再检查一下就好了。你会惊讶于在野外有多少违反规范的有缺陷的客户机

--

总体代码看起来很好,与其他代码大致相当。我看不出马上有什么不对劲。这让我怀疑这里的问题是TCP流;不明显的是,您的方法正在做任何事情来报告这个帧在逻辑上应该消耗多少字节,即总头长度加上有效负载长度。与我的代码相比,这将是
out int headerLength
frame.PayloadLength
的组合


我想知道是不是在一个
Read
调用中收到了多条消息(在TCP中非常正常),第一条消息被消耗掉了,而整个
字节被错误地当作消耗掉了。这意味着您开始读取下一帧标题的错误位置。单个
Read
invoke可以返回一个帧、一个帧或多个帧的片段-除非套接字已关闭,否则它唯一不能返回的是0字节。

感谢您的关注!我已经根据你提到的内容更新了我的上述帖子,很明显我遗漏了什么,具体是什么?我想我需要弄清楚!根据您在评论/聊天中的建议,我对解码逻辑进行了极大的更新,但在超过65535字节的情况下,仍然无法获得正确的数据。但当我尝试Firefox的最终逻辑时,我正确地获得了所有数据!非常感谢你们,而且,我仍然需要弄清楚如何处理有bug的Chrome客户端!谢谢@bcop好吧,我能说的就是:我不知道chrome有什么特别的问题。是的,你绝对需要担心单个块中的多个帧。附加观察:您的解码逻辑正在处理阵列的其余部分,但它应该只查看“dataLength”许多字节。坦率地说,我认为你可能只处理一个帧的一部分,即数据长度可能是12000,但是字节只有2048长。比较dataLength和decoded.Length——如果它们不相同,则说明问题非常严重。大型有效负载在单个读取调用中到达是非常罕见的,因此很可能只有部分有效负载;在这种情况下,您可能不应该尝试解码为文本,直到您
Message received on: 12/29/2017 1:02:51 PM
Text Frame received
Final frame received
Masked bit SET
Message received on: 12/29/2017 1:02:51 PM
Reserved Frame received
I wonder if what is happening is that you're getting multiple messages in a single Read call (perfectly normal in TCP), consuming the first message, and incorrectly treating the entire bytes as consumed.