You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中基于消息头动态设置ReceiveAsync的缓冲区大小?

基于前缀长度的TCP消息异步读取实现

针对可变长度消息的读取需求,核心逻辑是分两步完成:先完整读取4字节的长度前缀,再根据前缀指定的长度读取完整消息体。由于TCP是面向流的协议,单次ReceiveAsync可能无法获取全部所需数据,因此需要循环读取直到满足字节数要求。

实现步骤

  • 读取长度前缀:创建4字节缓冲区,循环调用ReceiveAsync,直到读取到完整的4字节前缀。
  • 解析消息长度:将读取到的4字节转换为整数(需注意与客户端约定的字节序,大端/小端)。
  • 读取完整消息体:根据解析出的长度创建对应大小的缓冲区,循环读取直到获取全部消息内容。

修改后的完整代码

Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
var localEndPoint = new IPEndPoint(ipAddress, 11000);
listener.Bind(localEndPoint);
listener.Listen(10);

while (true)
{
    Socket clientSocket = await listener.AcceptAsync();
    try
    {
        // 1. 读取4字节的消息长度前缀
        byte[] lengthBuffer = new byte[4];
        int totalRead = 0;
        while (totalRead < 4)
        {
            int bytesRead = await clientSocket.ReceiveAsync(lengthBuffer.AsMemory(totalRead, 4 - totalRead), SocketFlags.None);
            if (bytesRead == 0)
            {
                // 客户端断开连接
                clientSocket.Close();
                goto NextClient;
            }
            totalRead += bytesRead;
        }

        // 2. 解析消息长度(默认小端字节序,若客户端用大端则反转数组)
        if (!BitConverter.IsLittleEndian) Array.Reverse(lengthBuffer);
        int messageLength = BitConverter.ToInt32(lengthBuffer, 0);

        // 3. 读取完整的消息内容
        byte[] messageBuffer = new byte[messageLength];
        totalRead = 0;
        while (totalRead < messageLength)
        {
            int bytesRead = await clientSocket.ReceiveAsync(messageBuffer.AsMemory(totalRead, messageLength - totalRead), SocketFlags.None);
            if (bytesRead == 0)
            {
                // 客户端断开,消息不完整
                clientSocket.Close();
                goto NextClient;
            }
            totalRead += bytesRead;
        }

        // 此处处理读取到的完整消息
        // Extract data from messageBuffer
    }
    catch (Exception ex)
    {
        // 处理连接异常等情况
        clientSocket.Close();
    }
NextClient:;
}

关键细节说明

  • 循环读取的必要性:TCP数据可能被拆分为多个数据包发送,单次ReceiveAsync仅能获取部分数据,必须循环读取直到凑齐所需字节数。
  • 字节序适配:不同系统或客户端可能使用不同字节序,需与客户端约定一致;若客户端用大端序,需反转长度数组后再转换为整数。
  • 断开连接处理:当ReceiveAsync返回0时,说明客户端已主动断开,需及时关闭Socket并终止当前处理流程。

内容的提问来源于stack exchange,提问作者Bert54

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 20:22:35