使用Socket.ReceiveAsync(Memory<byte>)接收时内存无内容的问题排查
TCP ReceiveAsync(Memory)返回有效长度但缓冲区无数据的问题排查与解决
问题描述
在TCP接收编程中,使用ReceiveAsync(Memory<byte>, SocketFlags, CancellationToken)重载方法时,返回的reclen大于0,但目标缓冲区tcpRecReserve中未发现接收的数据;切换到ReceiveAsync(ArraySegment<byte>, SocketFlags)重载后,数据能正常写入tcpRecReserve。
相关代码:
public async Task BeginTcpRecieve() { try { //ArraySegment<byte> bytes = new ArraySegment<byte>(tcpRecReserve,catchNum, tcpRecReserve.Length - catchNum); Memory<byte> memory = new Memory<byte>(tcpRecReserve, catchNum, tcpRecReserve.Length - catchNum); int reclen = await tcpSocket.ReceiveAsync(memory, SocketFlags.None); HandleReceive(reclen); await BeginTcpRecieve(); } catch (SocketException e) { print(e.ErrorCode + "/" + e.Message); isConnected= false; } }
问题原因
- Memory
的偏移特性 :你创建的Memory<byte>是基于tcpRecReserve数组从catchNum索引位置开始的子段,接收的数据会写入这个子段的起始位置(即tcpRecReserve[catchNum]及之后的区域),而非数组的开头。如果调试时只查看tcpRecReserve数组的起始部分,会误以为没有数据。 - 调试工具的显示差异:部分调试工具对
Memory<byte>的可视化不如ArraySegment<byte>直观,容易忽略其偏移属性,导致误判数据未写入。 - 数据处理逻辑遗漏偏移:
HandleReceive方法如果直接处理整个tcpRecReserve数组,而非catchNum偏移后的区域,会导致无法读取到实际接收的数据。
解决方法
- 调整调试查看位置:调试时重点查看
tcpRecReserve数组中从catchNum索引开始的连续reclen个字节,确认数据是否写入。 - 修正数据处理逻辑:在调用
HandleReceive时传入偏移量和实际接收长度,确保处理的是正确的缓冲区区域,示例修改如下:
// 修改BeginTcpRecieve中的调用逻辑 HandleReceive(catchNum, reclen); // 对应调整HandleReceive方法 private void HandleReceive(int offset, int length) { // 提取实际接收的数据段 Span<byte> receivedSpan = tcpRecReserve.AsSpan(offset, length); // 后续数据处理逻辑... }
- 统一缓冲区构造参数:确保
Memory<byte>的构造参数(偏移量、长度)和之前ArraySegment<byte>完全一致,维持相同的缓冲区操作逻辑。
内容的提问来源于stack exchange,提问作者Nocpe
相关产品推荐
相关产品推荐

