websocket 的 ReceiveAsync 方法不会等待整个消息 [英] A websocket's ReceiveAsync method does not await the entire message

查看:33
本文介绍了websocket 的 ReceiveAsync 方法不会等待整个消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过 websocket 接收 JSON.至少:我是部分的.使用在线 websocket 服务,我收到了完整的 JSON 响应(所有 HTML 标记都被忽略).当我查看控制台中收到的 JSON 时,我可以看到 HTML 标记(在调试期间使用 HTML 查看器查看会删除 HTML),但它突然结束(数据不完整).

我的缓冲区有足够的空间,我正在使用 async-await(据说)在继续之前等待整个响应进入.

私有异步任务Receive(){var 缓冲区 = 新字节 [4096 * 20];while (_socket.State == WebSocketState.Open){var response = await _socket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None);if (response.MessageType == WebSocketMessageType.Close){等待_socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "收到关闭响应",CancellationToken.None);}别的{var 结果 = Encoding.UTF8.GetString(buffer);var a = 缓冲区[1000];var b = 缓冲区[10000];var c = 缓冲区[50000];var d = 缓冲区 [81000];Console.WriteLine(result);var responseObject = JsonConvert.DeserializeObject(result, _requestParameters.ResponseDataType);OnSocketReceive.Invoke(this, new SocketEventArgs {Response = responseObject });缓冲区=新字节[4096 * 20];}}}

注意事项:缓冲区足够大,bcd 永远不会被填满.我还应该注意,这只发生在 1-questions-newest-tag-java 请求中,155-questions-active 工作得很好.

在做了一些挖掘之后我发现 response.CloseStatusresponse.CloseStatusDescription 总是 null, response.Count 总是 1396(在 Word 中复制粘贴结果确实显示总是有 1396 个字符)并且 response.EndOfMessagefalse.

深入研究一些源代码我发现 DefaultReceiveBufferSize16 * 1024(足够大)并且 WebSocketGetDefaultKeepAliveInterval() 指的是 外部实现(但调试器显示00:00:30).

这不是超时问题,因为调试器在在线服务收到响应的同时停止.

为什么我的方法在套接字还没有收到所有数据时继续执行?

解决方案

我可能错了,但我认为您不应该总是立即收到完整的 WebSocket 消息.服务器可能会分块发送消息(这对应于使用 endOfMessage: false 调用 SendAsync).

因此,在循环中执行 await _socket.ReceiveAsync() 并累积接收到的块,直到 WebSocketReceiveResult.EndOfMessagetrue 或发生错误.

附带说明,您可能应该使用 WebSocket.CreateClientBuffer 而不是 new ArraySegment(buffer).

I am receiving JSON through a websocket. At least: I am partially. Using an online websocket service I receive the full JSON response (all the HTML markup is ignored). When I look at the JSON that I receive in my console I can see the HTML markup (viewing it with the HTML viewer during debugging removes the HTML) but it ends abruptly (incomplete data).

My buffer has plenty of space and I am using async-await to (supposedly) wait for the entire response to come in before continuing.

private async Task Receive()
{
  var buffer = new byte[4096 * 20];

  while (_socket.State == WebSocketState.Open)
  {
      var response = await _socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

      if (response.MessageType == WebSocketMessageType.Close)
      {
          await
              _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close response received",
                  CancellationToken.None);
      }
      else
      {
          var result = Encoding.UTF8.GetString(buffer);
          var a = buffer[1000];
          var b = buffer[10000];
          var c = buffer[50000];
          var d = buffer[81000];
          Console.WriteLine(result);
          var responseObject = JsonConvert.DeserializeObject<Response>(result, _requestParameters.ResponseDataType);

          OnSocketReceive.Invoke(this, new SocketEventArgs {Response = responseObject });
          buffer = new byte[4096 * 20];
      }
  }
}   

Things to note: The buffer is perfectly big enough and b, c and d are never filled. I should also note that this only happens for the 1-questions-newest-tag-java request, 155-questions-active works perfectly fine.

After doing some digging I have found that response.CloseStatus and response.CloseStatusDescription are always null, response.Count is always 1396 (copy-pasting the result in Word does show that there are always 1396 characters) and response.EndOfMessage is false.

Digging through some source code I have found that the DefaultReceiveBufferSize is 16 * 1024 (big enough) and the WebSocketGetDefaultKeepAliveInterval() refers to an external implementation (but the debugger shows 00:00:30).

It is not a matter of timeout since the debugger halts at the same moment the online service receives its response.

Why is my method continuing to execute when the socket has not yet received all data?

解决方案

I might be wrong, but I don't think you're always supposed to receive a complete WebSocket message at once. The server may be sending the message in chunks (that'd correspond to calling SendAsync with endOfMessage: false).

So, do await _socket.ReceiveAsync() in a loop and accumulate the received chunks, until WebSocketReceiveResult.EndOfMessage is true or an error has occured.

On a side note, you probably should be using WebSocket.CreateClientBuffer instead of new ArraySegment<byte>(buffer).

这篇关于websocket 的 ReceiveAsync 方法不会等待整个消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆