c#TCP服务器粘包

c#TCP服务器
TCP本身有头尾,如下图所示

img


但是使用socket Receive接收的时候,只会读到缓存区的内容,就会导致客户端发送是一包的,但是服务器接收会粘连在一起,有别的写法服务器就是按照TCP头尾这样一包一包接收的吗

https://www.cnblogs.com/wangjun8868/p/7160661.html

  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/4645072
  • 以下回答由chatgpt基于相关博客总结生成:

    对于TCP粘包问题,有以下几种解决办法:

    1.定长分包:即每一个数据包都规定了一个固定的长度。在服务端接收数据时,每次读取固定长度的数据,直到读取到所有数据。这种方法简单粗暴,代码实现也较为简单,但是存在一些弊端:比如当接收数据的长度不够固定长度时,需要等待缓冲区填满,此时会出现阻塞等待的情况。即使缓冲区已经填满,有时也会出现最后一个数据包不满固定长度的情况,需要特殊处理。

    2.特殊分隔符分包:即定义特殊字符或字符集合用作分隔符,当服务端接收到这个分隔符时,就可以确定一个数据包已经完成。这种方法也有一些弊端:比如特殊字符出现在数据体中,就会出现分包错误。

    3.消息头+消息体分包:可以在消息头中定义消息体长度,服务端在接收到消息头后,就可以知道消息体的长度,在读取完整的消息体之后,再进行处理。这种方法相对更加安全可靠。

    以下是使用第三种方法的示例代码:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;
    
    public class Server
    {
        private TcpListener _server;
        private List<TcpClient> _clients = new List<TcpClient>();
        private bool _isRunning = false;
    
        public Server(int port)
        {
            _server = new TcpListener(IPAddress.Any, port);
        }
    
        public void Start()
        {
            _server.Start();
            _isRunning = true;
            Console.WriteLine("Server started");
    
            while (_isRunning)
            {
                if (_server.Pending())
                {
                    TcpClient client = _server.AcceptTcpClient();
                    Console.WriteLine("Client connected: {0}", client.Client.RemoteEndPoint);
    
                    Thread t = new Thread(() => HandleClient(client));
                    t.Start();
                }
                Thread.Sleep(10);
            }
        }
    
        public void Stop()
        {
            _isRunning = false;
            _server.Stop();
            foreach (TcpClient client in _clients)
                client.Close();
            Console.WriteLine("Server stopped");
        }
    
        private void HandleClient(TcpClient client)
        {
            _clients.Add(client);
            BinaryReader reader = new BinaryReader(client.GetStream());
            while (client.Connected)
            {
                try
                {
                    // 读取消息头
                    int length = reader.ReadInt32();
                    // 读取消息体
                    byte[] buffer = reader.ReadBytes(length);
                    // 处理消息
                    ProcessMessage(buffer);
    
                }
                catch (EndOfStreamException)
                {
                    break;
                }
                catch (IOException e)
                {
                    Console.WriteLine("IOException: {0}", e.Message);
                    break;
                }
                Thread.Sleep(10);
            }
            _clients.Remove(client);
            client.Close();
            Console.WriteLine("Client disconnected: {0}", client.Client.RemoteEndPoint);
        }
    
        private void ProcessMessage(byte[] message)
        {
            // 处理消息
        }
    }