websocket's ReceiveAsync方法不等待整个消息



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

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

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];
      }
  }
}   

注意事项:缓冲区足够大,b, cd永远不会被填满。我还应该注意,这只发生在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)。

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

为什么当套接字尚未接收到所有数据时,我的方法继续执行?

为了完成@Noseratio响应,代码应该是这样的:

ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result= null;
using (var ms = new MemoryStream())
{
     do
     {
         result = await socket.ReceiveAsync(buffer, CancellationToken.None);
         ms.Write(buffer.Array, buffer.Offset, result.Count);
     }
     while (!result.EndOfMessage);
     ms.Seek(0, SeekOrigin.Begin);
     if (result.MessageType == WebSocketMessageType.Text)
     {
          using (var reader = new StreamReader(ms, Encoding.UTF8))
          {
               // do stuff
          }
     }
}

欢呼。

我可能错了,但我不认为你总是应该立即收到完整的WebSocket消息。服务器可能以块的形式发送消息(这相当于用endOfMessage: false调用SendAsync)。

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

顺便说一句,您可能应该使用WebSocket.CreateClientBuffer而不是new ArraySegment<byte>(buffer)

// Read the bytes from the web socket and accumulate all into a list.
var buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = null;
var allBytes = new List<byte>();
do
{
    result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
    for (int i = 0; i < result.Count; i++)
    {
        allBytes.Add(buffer.Array[i]);
    }
}
while (!result.EndOfMessage);
// Optional step to convert to a string (UTF-8 encoding).
var text = Encoding.UTF8.GetString(allBytes.ToArray(), 0, allBytes.Count);

根据Noseratio的回答,我实现了一个临时缓冲区,它将构造整个消息的数据。

var temporaryBuffer = new byte[BufferSize];
var buffer = new byte[BufferSize * 20];
int offset = 0;
WebSocketReceiveResult response;
while (true)
{
    response = await _socket.ReceiveAsync(
                         new ArraySegment<byte>(temporaryBuffer), 
                         CancellationToken.None);
    temporaryBuffer.CopyTo(buffer, offset);
    offset += response.Count;
    temporaryBuffer = new byte[BufferSize];
    if (response.EndOfMessage)
    {
        break;
    }
}

这里完全实现

试试这个:

try
{
    WebSocketReceiveResult result;
    string receivedMessage = "";
    var message = new ArraySegment<byte>(new byte[4096]);
    do
    {
        result = await WebSocket.ReceiveAsync(message, DisconectToken);
        if (result.MessageType != WebSocketMessageType.Text)
            break;
        var messageBytes = message.Skip(message.Offset).Take(result.Count).ToArray();
        receivedMessage += Encoding.UTF8.GetString(messageBytes);                    
    }
    while (!result.EndOfMessage);
    if (receivedMessage != "{}" && !string.IsNullOrEmpty(receivedMessage))
    {
        ResolveWebSocketResponse.Invoke(receivedMessage, Connection);
        Console.WriteLine("Received: {0}", receivedMessage);
    }
}
catch (Exception ex)
{
    var mes = ex.Message;
}

相关内容

  • 没有找到相关文章

最新更新