Javascript - 当服务器发送大响应时,WebSocket 客户端未收到 onmessage 事件

Posted

技术标签:

【中文标题】Javascript - 当服务器发送大响应时,WebSocket 客户端未收到 onmessage 事件【英文标题】:Javascript - WebSocket client not receiving onmessage event when server sends large response 【发布时间】:2020-10-29 15:12:36 【问题描述】:

我正在创建基于 TcpClient 和 NetworkStream 与 javascript 客户端通信的 .net websocket 服务器。握手后,客户端要求服务器执行特定操作,服务器生成响应 - 到目前为止,它是短 JSON 字符串被发送回客户端 - 并且工作正常。

在我要求发送更大的字符串响应(即,具有 200k 和更多字节的 base64 编码图像)之后,客户端停止接收响应并且没有触发 onmessage 事件。如果我切换并发送短 json - 它再次正常工作。

当我发送大数据时:

当我发送简单数据时:

客户端我从所有不相关的东西中剥离了代码(行为保持不变)

try
    ws = new WebSocket("ws://127.0.0.1:8282");
    ws.binaryType = "arraybuffer";

catch(err)
    debugger;
    document.getElementById("message").innerhtml = "Not Connected! " + err;         
;
ws.onopen = function () 
    var jsonRequest = '"action" : "START_STREAM","timeout"  : 20';
    ws.send("START_STREAM");
;

在服务器端,我在生成响应后隔离了代码(带有base64编码图像的纯字符串,我测试并正确解码):

 Byte[] frame = CreateFrameFromString(serverResponse);
 networkStream.Write(frame, 0, frame.Count());
 networkStream.Flush();
 clientSocket.Close();
 clientSocket = ServerListener.AcceptTcpClient();
 networkStream = clientSocket.GetStream();

初始化服务器线程的代码:

 ServerListener.Start();
 clientSocket = ServerListener.AcceptTcpClient();
 NetworkStream networkStream = clientSocket.GetStream();
 while (true)
    
     if (!networkStream.DataAvailable)
  ...regular loop/server stuff/handshake etc.

方法 CreateFrameFromString 如下。使用值 0-10 测试操作码,并且在所有情况下行为都是相同的 - 客户端没有捕获到响应。

 private static byte[] CreateFrameFromString(string message, Opcode opcode = Opcode.Text)
    
        var payload = Encoding.UTF8.GetBytes(message);

        byte[] frame;

        if (payload.Length < 126)
        
            frame = new byte[1 /*op code*/ + 1 /*payload length*/ + payload.Length /*payload bytes*/];
            frame[1] = (byte)payload.Length;
            Array.Copy(payload, 0, frame, 2, payload.Length);
        
        else if (payload.Length >= 126 && payload.Length <= 65535)
        
            frame = new byte[1 /*op code*/ + 1 /*payload length option*/ + 2 /*payload length*/ + payload.Length /*payload bytes*/];
            frame[1] = 126;
            frame[2] = (byte)((payload.Length >> 8) & 255);
            frame[3] = (byte)(payload.Length & 255);
            Array.Copy(payload, 0, frame, 4, payload.Length);
        
        else
        
            frame = new byte[1 /*op code*/ + 1 /*payload length option*/ + 8 /*payload length*/ + payload.Length /*payload bytes*/];
            frame[1] = 127; // <-- Indicates that payload length is in following 8 bytes.
            frame[2] = (byte)((payload.Length >> 56) & 255);
            frame[3] = (byte)((payload.Length >> 48) & 255);
            frame[4] = (byte)((payload.Length >> 40) & 255);
            frame[5] = (byte)((payload.Length >> 32) & 255);
            frame[6] = (byte)((payload.Length >> 24) & 255);
            frame[7] = (byte)((payload.Length >> 16) & 255);
            frame[8] = (byte)((payload.Length >> 8) & 255);
            frame[9] = (byte)(payload.Length & 255);
            Array.Copy(payload, 0, frame, 10, payload.Length);
        

        frame[0] = (byte)((byte)opcode | 0x80 /*FIN bit*/);

        return frame;
    

我是否遗漏了什么——协议/缓冲区大小/等等?在测试时,我注意到我可以使用上述设置发送最多 4250 个字符的响应,无需修改。一旦我达到这个数字,响应就开始消失。

【问题讨论】:

【参考方案1】:

经过大量故障排除后,我发现我必须以包的形式发送数据,而不是整体发送。我将响应分成块(50000 个字符)并逐个发送,而在客户端,我在 onmessage 事件中拾取碎片。发送完所有响应块后,我关闭了会话 - 这在客户端触发了从 base64 流创建图像。

【讨论】:

以上是关于Javascript - 当服务器发送大响应时,WebSocket 客户端未收到 onmessage 事件的主要内容,如果未能解决你的问题,请参考以下文章

当服务中的事件被触发时,如何将响应从服务发送回客户端?

Java servlet 对 JavaScript 的响应 [重复]

当 JSON 作为响应发送但使用纯字符串时,Go 并发 TCP 服务器挂起

AJAX

无法使用javascript向ASP.NET web api Controller发送http POST请求

Ajax的基本请求/响应模型