2017-01-28 14 views
2

Я пишу приложение C#, которое подключается к серверу websocket, и получает ответ JSON неизвестного размера. Для этой цели я использую класс ClientWebSocket.Выбор размера буфера для ответа WebSocket

Единственный способ получить данные от клиента, кажется, с ReceiveAsync методом, который принимает ArraySegment<byte> в качестве аргумента:

var client = new ClientWebSocket(); 
client.ConnectAsync(new Uri($"ws://localhost:{port}"), token).Wait(); 
var result = new ArraySegment<byte>(new byte[1000]); 
client.ReceiveAsync(result, token).Wait(); 

Проблема в том, так как я не знаю, как большой формат JSON ответ будет, я не знаю, как большой сделать буфер, поддерживающий этот массив ArraySegment. В этом случае я указал 1000 байтов, что слишком мало, и ответ усечен. Однако я беспокоюсь, что если я задаю размер буфера как произвольно большой (1,000,000 байт?), Я буду использовать больше памяти, чем мне нужно.

Как выбрать размер буфера, не зная размер ответа?

ответ

3

Если я правильно понял API, он предоставит вам сообщение веб-узла в нескольких частях, если необходимо.

Это означает, что если сообщение посылается от сервера 2048 байт и используется 1024 байт буфера и делать:

var buffer = new ArraySegment<byte>(new byte[1000]); 
var result = await client.ReceiveAsync(buffer, token); 

Тогда в этом первом вызове result.Count будет установлен в 1000 и result.EndOfMessage будет установлен в false. Это означает, что вам нужно продолжить чтение до тех пор, пока значение EndOfMessage не будет равно true, что означает, что для этого примера читается 3.

Если вам нужно все в одном буфере и не может жить с обработкой фрагментов сообщения индивидуально, вы можете начать с небольшого буфера и изменить размер буфера приема, если результат подскажет вам, что больше данных поступает. Таким образом, вы также можете убедитесь, что при превышении максимального размера прием остановлен.

var buffer = new byte[1000]; 
var offset = 0; 
var free = buffer.Length; 
while (true) 
{ 
    var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer, offset, free), token); 
    offset += result.Count; 
    free -= result.Count; 
    if (result.EndOfMessage) break; 
    if (free == 0) 
    { 
     // No free space 
     // Resize the outgoing buffer 
     var newSize = buffer.Length + xyz; 
     if (newSize > maxFrameSize) 
     { 
      throw new Exception ("Maximum size exceeded"); 
     } 
     var newBuffer = new buffer[newSize]; 
     Array.Copy(buffer, 0, newBuffer, 0, offset); 
     buffer = newBuffer; 
     free = buffer.Length - offset; 
    } 
} 

И, конечно, вы должны также проверить другие поля в приемном результате, как MessageType.