Метод ReceiveAsync websocket не ожидает всего сообщения
я получаю JSON через websocket. По крайней мере, частично. Используя онлайн-сервис 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
, c
и d
никогда не заполнены. Я также должен отметить, что это происходит только в 1-questions-newest-tag-java
запрос 155-questions-active
работает прекрасно.
после некоторых раскопок я нашел, что response.CloseStatus
и response.CloseStatusDescription
всегда null
, response.Count
всегда 1396
(копирование-вставка результата в Word показывает, что всегда есть 1396 символов) и response.EndOfMessage
is false
.
копаясь некоторые исходный код я обнаружил, что DefaultReceiveBufferSize
is 16 * 1024
(достаточно большой) и WebSocketGetDefaultKeepAliveInterval()
относится к внешнего внедрения (но отладчик показывает 00:00:30
).
это не вопрос времени ожидания, так как отладчик останавливается в тот же момент, когда онлайн-служба получает свой ответ.
почему мой метод продолжает выполняться, когда гнездо еще не получил все данные?
5 ответов
Я могу ошибаться, но я не думаю, что вы всегда должны получать полный WebSocket
сообщение сразу. Сервер может отправлять сообщение кусками (это соответствует вызову SendAsync
С endOfMessage: false
).
Итак,await _socket.ReceiveAsync()
в цикле и накапливать полученные куски, пока WebSocketReceiveResult.EndOfMessage
is true
или произошла ошибка.
на боковой ноте, вы, вероятно, должны использовать WebSocket.CreateClientBuffer
вместо new ArraySegment<byte>(buffer)
.
чтобы завершить ответ @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
}
}
}
Ура.
после ответа 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;
}
}
полной реализации здесь
// 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);
попробуйте это:
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;
}