Фрагменты WebSocket в C#
Один логический текст WebSocket может прийти
несколькими вызовами ReceiveAsync, пока
EndOfMessage не станет true.
Если буфер меньше сообщения, первые чтения
дают EndOfMessage: false.
Отправим на echo-сервис длинную строку и примем
её буфером на 32 байта в цикле.
Сегменты складывают в MemoryStream или
список, затем декодируют UTF-8 целиком - длина
совпадёт с отправленной:
using System.Net.WebSockets;
using System.Text;
using ClientWebSocket client = new();
using CancellationTokenSource cts = new(TimeSpan.FromSeconds(8));
await client.ConnectAsync(new Uri("wss://echo.websocket.events"), cts.Token);
string sent = new('x', 120);
byte[] outbound = Encoding.UTF8.GetBytes(sent);
await client.SendAsync(outbound, WebSocketMessageType.Text, true, CancellationToken.None);
using MemoryStream acc = new();
byte[] chunk = new byte[32];
while (true)
{
WebSocketReceiveResult part = await client.ReceiveAsync(chunk, CancellationToken.None);
acc.Write(chunk, 0, part.Count);
if (part.EndOfMessage)
{
break;
}
}
string got = Encoding.UTF8.GetString(acc.ToArray());
Console.WriteLine(got.Length);
Console.WriteLine(got == sent);
Маленький буфер в примере выше - учебный приём,
на практике размер берут с запасом. Склейку
фрагментов можно проверить и без сети: куски
байтов пишут в MemoryStream по порядку
и декодируют целиком:
using System.Text;
var parts = new List<byte[]>
{
Encoding.UTF8.GetBytes("hel"),
Encoding.UTF8.GetBytes("lo")
};
using MemoryStream acc = new();
foreach (byte[] p in parts)
{
acc.Write(p, 0, p.Length);
}
Console.WriteLine(Encoding.UTF8.GetString(acc.ToArray()));
Отправьте на echo-сервис строку из 90
букв "y", примите её порциями по
20 байт и выведите, сколько чтений
понадобилось, чтобы собрать текст целиком.