Websocket 以大消息关闭

Posted

技术标签:

【中文标题】Websocket 以大消息关闭【英文标题】:Websocket closes with large messages 【发布时间】:2015-12-02 01:34:08 【问题描述】:

我正在编写一个 c# web socket 实现,并且每当我发送大于 65535 字节的消息时;客户端(javascript)无法加载消息并关闭连接。 (之前说的是无效帧,现在什么都没有了)

我正在像这样对消息进行编码

public static Byte[] EncodeMessageToSend(String message)
    
        Byte[] response;
        Byte[] bytesRaw = Encoding.UTF8.GetBytes(message);
        Byte[] frame = new Byte[10];

        Int32 indexStartRawData = -1;
        Int32 length = bytesRaw.Length;

        frame[0] = (Byte)129;
        if (length <= 125)
        
            frame[1] = (Byte)length;
            indexStartRawData = 2;
        
        else if (length >= 126 && length <= 65535)
        
            frame[1] = (Byte)126;
            frame[2] = (Byte)((length >> 8) & 255);
            frame[3] = (Byte)(length & 255);
            indexStartRawData = 4;
        
        else
        
            frame[1] = (Byte)127;
            frame[2] = (Byte)((length >> 56) & 255);
            frame[3] = (Byte)((length >> 48) & 255);
            frame[4] = (Byte)((length >> 40) & 255);
            frame[5] = (Byte)((length >> 32) & 255);
            frame[6] = (Byte)((length >> 24) & 255);
            frame[7] = (Byte)((length >> 16) & 255);
            frame[8] = (Byte)((length >> 8) & 255);
            frame[9] = (Byte)(length & 255);

            indexStartRawData = 10;
        

        response = new Byte[indexStartRawData + length];

        Int32 i, reponseIdx = 0;

        //Add the frame bytes to the reponse
        for (i = 0; i < indexStartRawData; i++)
        
            response[reponseIdx] = frame[i];
            reponseIdx++;
        

        //Add the data bytes to the response
        for (i = 0; i < length; i++)
        
            response[reponseIdx] = bytesRaw[i];
            reponseIdx++;
        

        return response;
    

65535 字节以下的消息可以正常发送。任何帮助表示赞赏。

澄清我试图发送的消息是 120283 字节;错误代码为 1006

对于最多 125 个字节的消息,代码是正确的。 对于消息 > 125 但

如您所见,我在上面的代码中完成了所有这些操作,但消息发送失败。

【问题讨论】:

您看起来会从 miscutil (nuget) 中 Jon Skeet 的 EndianBitConverter 中受益,这将使您的代码更易于阅读。 【参考方案1】:

这似乎有一个错误:

frame[1] = (Byte)127;

frame[2] = (Byte)((length >> 56) & 255);
frame[3] = (Byte)((length >> 48) & 255);
frame[4] = (Byte)((length >> 40) & 255);
frame[5] = (Byte)((length >> 32) & 255);
frame[6] = (Byte)((length >> 24) & 255);
frame[7] = (Byte)((length >> 16) & 255);
frame[8] = (Byte)((length >> 8) & 255);
frame[9] = (Byte)(length & 255);

这是因为您试图将 32 位数字移位超过 8 个字节,即使 Int32 只有 4 个字节长。最终结果是,您最终在 8 个字节上存储了两次相同的 32 位数字。您可以将 length 转换为 ulong 并改用该值,您的代码应该可以工作。否则……

我更喜欢用别人的代码来做一些无聊的事情,比如位移。

这个位移代码(及其错误)已经传播得非常广泛(你不是第一个看到这个问题的人)。

如果您从 nuget 获取 Jon Skeet 的 MiscUtil,您将使用以下代码获得更好的结果(另外,它更易于阅读):

frame[1] = (byte)127;
EndianBitConverter.Big.CopyBytes((ulong)length, frame, 2);

【讨论】:

很棒,已修复。我自己并不喜欢原始代码,所以这是一个受欢迎的变化。【参考方案2】:

错误在于发送一个长变量,但长度是 Int32。 有几种方法可以解决,例如:

frame[1] = (Byte)127;
frame[2] = 0;
frame[3] = 0;
frame[4] = 0;
frame[5] = 0;
frame[6] = (Byte)((length >> 24) & 255);
frame[7] = (Byte)((length >> 16) & 255);
frame[8] = (Byte)((length >> 8) & 255);
frame[9] = (Byte)(length & 255);

我测试了这段代码并且工作正常!

【讨论】:

以上是关于Websocket 以大消息关闭的主要内容,如果未能解决你的问题,请参考以下文章

怎么在服务器端关闭websocket连接

websocket连接不上、报错、自动关闭,求解

使用websocket来监控是否异常退出或异常关闭登陆窗口

WebSocket - 关闭框架

Python 服务器 - 处理 WebSocket.close()

关闭连接到 Mojo websocket 的 Mojo::IOLoop 重复事件