C#中处理Socket粘包

在C#中使用Socket进行网络通信时,粘包问题是常见的。粘包问题通常发生在TCP协议中,因为TCP是流式协议,数据可能会被分割成多个包发送,也可能多个小包会被合并成一个大包接收。

处理粘包问题的常见方法是使用消息分隔符或消息长度前缀。以下是使用消息长度前缀来处理粘包问题的示例代码。

发送端代码

在发送端,每条消息的前面加上一个固定长度的消息长度前缀。

cs 复制代码
using System;
using System.Net.Sockets;
using System.Text;

public class Client
{
    public static void SendMessage(Socket socket, string message)
    {
        byte[] messageBytes = Encoding.UTF8.GetBytes(message);
        byte[] lengthPrefix = BitConverter.GetBytes(messageBytes.Length);

        byte[] packet = new byte[lengthPrefix.Length + messageBytes.Length];
        Buffer.BlockCopy(lengthPrefix, 0, packet, 0, lengthPrefix.Length);
        Buffer.BlockCopy(messageBytes, 0, packet, lengthPrefix.Length, messageBytes.Length);

        socket.Send(packet);
    }
}

接收端代码

在接收端,首先读取消息长度前缀,然后根据长度前缀读取完整的消息。

cs 复制代码
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Server
{
    private const int LengthPrefixSize = 4;

    public static void StartListening()
    {
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 11000);
        Socket listener = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(10);

            while (true)
            {
                Socket handler = listener.Accept();
                ProcessClient(handler);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void ProcessClient(Socket handler)
    {
        byte[] buffer = new byte[1024];
        int bytesRead = 0;

        while (true)
        {
            // Read the length prefix
            bytesRead = handler.Receive(buffer, 0, LengthPrefixSize, SocketFlags.None);
            if (bytesRead == 0)
                break;

            int messageLength = BitConverter.ToInt32(buffer, 0);

            // Read the message
            int totalBytesRead = 0;
            byte[] messageBuffer = new byte[messageLength];
            while (totalBytesRead < messageLength)
            {
                bytesRead = handler.Receive(messageBuffer, totalBytesRead, messageLength - totalBytesRead, SocketFlags.None);
                if (bytesRead == 0)
                    break;

                totalBytesRead += bytesRead;
            }

            string message = Encoding.UTF8.GetString(messageBuffer);
            Console.WriteLine("Received: {0}", message);
        }

        handler.Shutdown(SocketShutdown.Both);
        handler.Close();
    }
}

解释

  • 发送端:
  • 将消息转换为字节数组。
  • 计算消息的长度,并将长度作为前缀添加到消息前面。
  • 发送带有长度前缀的消息。
  • 接收端:
  • 首先读取固定长度的消息长度前缀。
  • 根据长度前缀读取完整的消息。
  • 将消息转换为字符串并处理。

通过这种方式,可以有效地解决TCP通信中的粘包问题。

相关推荐
hez20103 天前
在 .NET 上构建超大托管数组
c#·.net·.net core·gc·clr
雨落倾城夏未凉8 天前
第四章c#方法-参数数组和可选参数(16)
后端·c#
唐青枫9 天前
线程不是越多越快:C#.NET Thread 生命周期、同步与后台工作线程实战
c#·.net
唐青枫10 天前
别只会反射:C#.NET Emit 动态生成代码实战详解
c#·.net
咕白m62510 天前
.NET 环境下 Word 超链接批量提取方案
c#·.net
用户917215619021110 天前
C# 通信协议增量解析:用状态机处理半包和粘包
c#
小码编匠11 天前
C# 工控上位机必备:数据转换工具类与十个核心模块
后端·c#·.net
唐青枫13 天前
别再乱用 StartNew:C#.NET TaskFactory 任务调度实战详解
c#·.net
Artech13 天前
[MAF预定义的AIContextProvider-03]ChatHistoryMemoryProvider——赋予Agent从经验中学习的能力
ai·c#·agent·memory·maf
Scout-leaf15 天前
C#摸鱼实录——IoC与DI案例详解
c#