为WebSocket响应选择缓冲区大小

Mig*_*ell 6 c# buffer json websocket clientwebsocket

我正在编写一个连接到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();
Run Code Online (Sandbox Code Playgroud)

问题是,因为我不知道JSON响应有多大,我不知道缓冲区支持ArraySegment有多大.在这种情况下,我指定了1000个字节,这个字节太小了,并且响应被截断了.但是我担心如果我将缓冲区大小设置为任意大(1,000,000字节?),我将占用更多的内存而不是我需要的内存.

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

Mat*_*247 7

如果我正确理解API,它将在必要时为您提供多个部分的websocket消息.

这意味着如果从服务器发送的消息是2048字节,并且您使用1024字节缓冲区并执行:

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

然后在此第一个调用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,您还应该检查接收结果中的其他字段,例如MessageType.

  • 一个让我措手不及的观察结果:非 EndOfMessage 块的 result.Count 值并不总是等于缓冲区大小。它可能更小。 (2认同)