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

相关推荐
“抚琴”的人9 小时前
【机械视觉】C#+VisionPro联合编程———【六、visionPro连接工业相机设备】
c#·工业相机·visionpro·机械视觉
大丈夫立于天地间9 小时前
ISIS协议中的数据库同步
运维·网络·信息与通信
Dream Algorithm9 小时前
路由器的 WAN(广域网)口 和 LAN(局域网)口
网络·智能路由器
IT猿手9 小时前
基于CNN-LSTM的深度Q网络(Deep Q-Network,DQN)求解移动机器人路径规划,MATLAB代码
网络·cnn·lstm
吴盐煮_9 小时前
使用UDP建立连接,会存在什么问题?
网络·网络协议·udp
hyshhhh10 小时前
【算法岗面试题】深度学习中如何防止过拟合?
网络·人工智能·深度学习·神经网络·算法·计算机视觉
FAREWELL0007510 小时前
C#核心学习(七)面向对象--封装(6)C#中的拓展方法与运算符重载: 让代码更“聪明”的魔法
学习·c#·面向对象·运算符重载·oop·拓展方法
Hellc00710 小时前
轮询、WebSocket 和 SSE:实时通信技术全面指南(含C#实现)
网络
xujiangyan_11 小时前
nginx的反向代理和负载均衡
服务器·网络·nginx