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通信中的粘包问题。

相关推荐
七夜zippoe1 分钟前
OpenClaw CLI 完整命令手册
linux·服务器·网络·cli·openclaw·命令手册
Sunsets_Red10 分钟前
乘法逆元的 exgcd 求法
c++·学习·数学·算法·c#·密码学·信息学竞赛
BUTCHER530 分钟前
Netty Channel 生命周期
java·服务器·网络
骥龙31 分钟前
第四篇:部署阶段安全加固——从裸奔到生产级防护
运维·网络·人工智能·安全
big_rabbit050238 分钟前
网络IO模型?什么是多路复用IO?select和epoll 的差别?
网络
唐青枫40 分钟前
深入理解 C#.NET TaskScheduler:为什么大量使用 Work-Stealing
c#·.net
野犬寒鸦1 小时前
从零起步学习计算机操作系统:I/O篇
服务器·开发语言·网络·后端·面试
人工智能AI技术1 小时前
Claude 3.7 企业版私有化部署技术验证:与 .NET 实战方案
人工智能·c#
跨境海王哥1 小时前
怎么检查一个IP是否干净?IP质量分数检测及如何判断风险?
网络·网络协议·tcp/ip
nainaire1 小时前
仿muduo库的Tcp服务器以及其应用层Http协议支持
服务器·网络·c++·tcp/ip·http