选择WebSocket响应的缓冲区大小

13

我正在编写一个连接到 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字节?),那么我将使用比所需更多的内存。

如何在不知道响应大小的情况下选择缓冲区大小?

1个回答

18

如果我正确理解API,那么它将在必要时将WebSocket消息拆分为多个部分。

这意味着,如果从服务器发送的消息为2048个字节,并且您使用了1000个字节的缓冲区并执行以下操作:

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


1
一个让我措手不及的观察:对于非EndOfMessage块,值result.Count并不总是等于缓冲区大小。它可能会更小。 - Øystein Kolsrud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接