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

Socket通信:如何维持连接并正确接收客户端数据?

Socket长连接通信问题修复

问题描述

尝试通过Socket实现服务端与客户端的长连接通信,需求如下:

  • 维持两者的连接,持续监听客户端发送的数据
  • 当客户端发送的数据包含"CLIENT[123]:"时,服务端回复输入内容;不符合条件则继续监听

但当前代码存在异常:启动服务端后,未收到客户端发送的数据却自动输出接收内容,且无法维持长连接。

原服务端代码

private static void server()
{   
    var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), Int32.Parse("8888"));
    // this socket listening connect from client
    var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    listener.Bind(localEndPoint);
    listener.Listen(10);
    var size = 1024;
    var receiveBuffer = new byte[size];
    while (true)
    {
        // this socket is receive/send data
        var socket = listener.Accept();
        var length = socket.Receive(receiveBuffer);
        socket.Shutdown(SocketShutdown.Receive);
        var text = Encoding.ASCII.GetString(receiveBuffer, 0, length);              
        Console.WriteLine($"Received from client: {text}");                    
        if (text.Contains("CLIENT[123]:"))
        {
            Console.Write("#Send to client >>> ");
            var reply = Console.ReadLine();
            var sendBuffer = Encoding.ASCII.GetBytes(reply);
            socket.Send(sendBuffer);
            socket.Shutdown(SocketShutdown.Send);
            socket.Close();
            Array.Clear(receiveBuffer, 0, size);
        }
    }
}

原客户端代码

private static void client()
{
    var serverEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), Int32.Parse("8888"));
    var size = 1024;
    var receiveBuffer = new byte[size];
    while (true)
    {
        Console.Write("#Send to server >>> ");
        var text = Console.ReadLine();
        var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        socket.Connect(serverEndpoint);
        var sendBuffer = Encoding.ASCII.GetBytes(text); 
        socket.Send(sendBuffer);
        socket.Shutdown(SocketShutdown.Send);
        
        //get data from server
        var length = socket.Receive(receiveBuffer);
        var result = Encoding.ASCII.GetString(receiveBuffer, 0, length);
        Array.Clear(receiveBuffer, 0, size);
        socket.Shutdown(SocketShutdown.Receive);
        socket.Close();
    }
}

客户端测试数据示例

CLIENT[123]: Hi server, are you ok ?

问题原因

  1. 短连接逻辑错误:原服务端每次接受连接后,处理完一次数据就关闭socket,无法维持长连接;客户端每次发送数据都新建socket,用完即关,同样无法保持连接。
  2. 错误的Shutdown调用:服务端在Receive()后立即调用Shutdown(SocketShutdown.Receive),直接关闭接收通道,导致后续无法监听客户端数据;客户端发送数据后关闭发送通道,服务端Receive()会返回0长度,此时空字符串被当成接收内容输出。
  3. 缓冲区清理不及时:服务端仅在符合条件时清理缓冲区,不符合条件时残留数据会干扰下一次接收。

修复方案

修复后的服务端代码

private static void server()
{
    var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), 8888);
    var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    listener.Bind(localEndPoint);
    listener.Listen(10);
    Console.WriteLine("服务端已启动,等待客户端连接...");

    // 接受客户端连接,复用该socket维持长连接
    Socket clientSocket = listener.Accept();
    Console.WriteLine("客户端已连接");
    var bufferSize = 1024;
    byte[] receiveBuffer = new byte[bufferSize];

    while (true)
    {
        // 每次接收前清空缓冲区
        Array.Clear(receiveBuffer, 0, bufferSize);
        int receiveLength = clientSocket.Receive(receiveBuffer);

        // 客户端断开连接时,Receive返回0,重新等待新连接
        if (receiveLength == 0)
        {
            Console.WriteLine("客户端已断开连接,等待新连接...");
            clientSocket.Close();
            clientSocket = listener.Accept();
            Console.WriteLine("新客户端已连接");
            continue;
        }

        string receivedText = Encoding.ASCII.GetString(receiveBuffer, 0, receiveLength);
        Console.WriteLine($"Received from client: {receivedText}");

        // 符合条件时回复客户端
        if (receivedText.Contains("CLIENT[123]:"))
        {
            Console.Write("#Send to client >>> ");
            string replyText = Console.ReadLine();
            byte[] sendBuffer = Encoding.ASCII.GetBytes(replyText);
            clientSocket.Send(sendBuffer);
        }
    }
}

修复后的客户端代码

private static void client()
{
    var serverEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), 8888);
    Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    try
    {
        clientSocket.Connect(serverEndpoint);
        Console.WriteLine("已成功连接到服务端");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"连接服务端失败: {ex.Message}");
        return;
    }

    var bufferSize = 1024;
    byte[] receiveBuffer = new byte[bufferSize];

    while (true)
    {
        Console.Write("#Send to server >>> ");
        string sendText = Console.ReadLine();

        // 输入exit可退出客户端
        if (sendText.Equals("exit", StringComparison.OrdinalIgnoreCase))
        {
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
            break;
        }

        byte[] sendBuffer = Encoding.ASCII.GetBytes(sendText);
        clientSocket.Send(sendBuffer);

        // 接收服务端回复(仅符合条件时会有回复)
        int receiveLength = clientSocket.Receive(receiveBuffer);
        if (receiveLength > 0)
        {
            string replyText = Encoding.ASCII.GetString(receiveBuffer, 0, receiveLength);
            Console.WriteLine($"Received from server: {replyText}");
            Array.Clear(receiveBuffer, 0, bufferSize);
        }
    }
}

修复说明

  • 长连接实现:服务端接受一次连接后,循环复用该socket进行通信;客户端仅创建一次socket,连接成功后持续使用。
  • 断开处理:服务端检测到Receive()返回0时,判定客户端断开,自动重新等待新连接。
  • 缓冲区管理:每次接收前强制清空缓冲区,避免残留数据干扰。
  • 移除无效Shutdown:仅在客户端退出时调用Shutdown(SocketShutdown.Both)关闭通道,保留正常通信的通道权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:17:24