我正在编写一个连接到websocket服务器的C#应用程序,并收到一个未知大小的JSON响应。我为此目的使用ClientWebSocket
类。
从客户端接收数据的唯一方法似乎是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字节?),我将耗尽比我需要的内存更多的内存。
如何在不知道响应大小的情况下选择缓冲区大小?
答案 0 :(得分:7)
如果我正确理解了API,它会在必要时为您提供多个部分的websocket消息。
这意味着如果从服务器发送的消息是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次读取。
如果您需要一个缓冲区中的所有内容并且不能单独处理消息片段,则可以从一个小缓冲区开始,并在结果告诉您有更多数据进入时调整接收缓冲区的大小。从而您可以还要检查是否超过最大尺寸,停止接收。
int bufferSize = 1000;
var buffer = new byte[bufferSize];
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 + bufferSize;
// Check if the new size exceeds a limit
// It should suit the data it receives
// This limit however has a max value of 2 billion bytes (2 GB)
if (newSize > maxFrameSize)
{
throw new Exception ("Maximum size exceeded");
}
var newBuffer = new byte[newSize];
Array.Copy(buffer, 0, newBuffer, 0, offset);
buffer = newBuffer;
free = buffer.Length - offset;
}
}
当然,您还应该检查接收结果中的其他字段,例如MessageType
。