如何使用System.Net.WebSockets处理超出缓冲区的分片数据收发
WebSocket 超缓冲区分片收发操作指引(基于.NET WebSocket API)
核心逻辑说明
WebSocket协议本身支持分片传输,ReceiveAsync和SendAsync的分片处理核心依赖API提供的EndOfMessage标志位判断消息是否传输完成,和你分配的缓冲区大小没有强制绑定,只要按照固定规则循环读写即可。
分片接收处理(WebSocket.ReceiveAsync)
操作步骤
- 提前初始化固定大小的缓冲区(你分配的容量上限),以及可动态扩容的临时存储容器(推荐
MemoryStream) - 循环调用
ReceiveAsync方法,每次将数据写入固定缓冲区 - 把本次接收到的有效数据(长度为返回结果的
Count属性)写入临时存储容器 - 检查返回结果的
EndOfMessage属性:为false则继续下一轮接收,为true则终止循环,临时存储容器中的内容就是完整的消息 - 文本消息必须等所有分片接收完成后再做编码转换,避免多字节字符被截断产生乱码
代码示例
// 固定分配的4KB缓冲区,可根据业务调整容量 var buffer = new byte[1024 * 4]; using var dataStream = new MemoryStream(); WebSocketReceiveResult receiveResult; do { receiveResult = await webSocket.ReceiveAsync( new ArraySegment<byte>(buffer), cancellationToken ); // 写入本次接收到的有效数据 await dataStream.WriteAsync(buffer, 0, receiveResult.Count, cancellationToken); } while (!receiveResult.EndOfMessage); // 读取完整消息 byte[] fullMessage = dataStream.ToArray(); // 如果是文本消息:string text = Encoding.UTF8.GetString(fullMessage);
分片发送处理(WebSocket.SendAsync)
操作步骤
- 先拿到完整的待发送数据,记录总长度,初始化已发送偏移量为0
- 每次取不超过缓冲区容量的数据切片作为单次发送内容
- 非最后一次发送时,
endOfMessage参数固定传false,最后一次发送传true - 每次发送完成后更新已发送偏移量,直到所有数据全部发送完成
代码示例
// 固定分配的4KB缓冲区,可根据业务调整容量 var buffer = new byte[1024 * 4]; // 待发送的完整数据,二进制消息直接传入字节数组即可 byte[] fullData = Encoding.UTF8.GetBytes("这里是长度超过4KB的大文本消息内容..."); int sentOffset = 0; while (sentOffset < fullData.Length) { // 计算单次发送的最大长度,不超过缓冲区容量 int sendSize = Math.Min(buffer.Length, fullData.Length - sentOffset); bool isLastSegment = sentOffset + sendSize >= fullData.Length; await webSocket.SendAsync( new ArraySegment<byte>(fullData, sentOffset, sendSize), WebSocketMessageType.Text, // 二进制消息改为 WebSocketMessageType.Binary isLastSegment, cancellationToken ); sentOffset += sendSize; }
注意事项
- 只有
EndOfMessage属性是判断消息是否收发完成的唯一可靠依据,不要通过单次接收/发送的数据长度是否等于缓冲区大小来判断 - 收发过程中需要捕获
WebSocketException异常,出现错误时按照协议规范关闭连接,避免资源泄漏 - 超大消息分片传输时建议设置合理的超时阈值,避免单个消息长时间占用连接
内容的提问来源于stack exchange,提问作者Elringus
相关产品推荐
相关产品推荐

