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

控制台应用中如何保持客户端Socket连接开放以收发多条消息

问题解决方案

核心问题根因

  • 原有示例为单次请求设计,执行完单轮收发后无阻塞逻辑,主流程直接结束导致程序退出
  • 接收回调逻辑冗余重复,ManualResetEvent接收完成信号未做重置,无法支持多轮接收
  • 无请求队列和响应匹配逻辑,无法应对请求堆叠、多请求响应对应的需求

具体修改步骤

1. 新增全局变量适配长连接场景

在AsynchronousClient类中新增线程安全的队列、计数和长连接Socket变量:

// 待发送请求队列,多线程场景下安全
private static ConcurrentQueue<string> _requestQueue = new ConcurrentQueue<string>();
// 当前请求剩余未接收的响应条数,每个请求对应2条
private static int _remainingResponseCount = 0;
// 保持长连接的全局Socket实例
private static Socket _connectedClient;

2. 修改主流程为循环监听模式

修改StartClient方法,连接成功后持续保持接收状态,主进程循环监听控制台输入:

public static void StartClient()
{
    try
    {
        IPEndPoint remoteEP = new IPEndPoint(ip, port);
        _connectedClient = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        // 建立和服务器的连接
        _connectedClient.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), _connectedClient);
        connectDone.WaitOne();
        // 启动全局持续接收逻辑
        Receive(_connectedClient);
        Console.WriteLine("连接成功,输入内容回车即可发送,输入exit可退出程序:");
        // 主循环监听控制台输入,阻塞主进程避免程序退出
        while(true)
        {
            var input = Console.ReadLine();
            if(input.Equals("exit", StringComparison.OrdinalIgnoreCase))
            {
                // 正常关闭连接后退出
                _connectedClient.Shutdown(SocketShutdown.Both);
                _connectedClient.Close();
                break;
            }
            if(!string.IsNullOrEmpty(input))
            {
                _requestQueue.Enqueue(input);
                Send(_connectedClient, input + "\r\n");
                sendDone.WaitOne();
                sendDone.Reset(); // 重置发送完成信号,支持后续多次发送
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

3. 修正接收回调逻辑

删除冗余的BeginReceive调用,新增响应分割、条数计数逻辑,适配单请求2条响应的需求:

private static void ReceiveCallback(IAsyncResult ar)
{
    try
    {
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.workSocket;
        int bytesRead = client.EndReceive(ar);
        if (bytesRead > 0)
        {
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
            var receivedContent = state.sb.ToString();
            // 按服务器响应分隔符拆分单条响应,默认按\r\n分割,可根据实际协议调整
            while(receivedContent.Contains("\r\n"))
            {
                var lineEndIndex = receivedContent.IndexOf("\r\n");
                var singleResponse = receivedContent.Substring(0, lineEndIndex);
                receivedContent = receivedContent.Substring(lineEndIndex + 2);
                Console.WriteLine($"收到响应:{singleResponse}");
                _remainingResponseCount--;
                // 当前请求的2条响应全部接收完成
                if(_remainingResponseCount == 0 && _requestQueue.TryDequeue(out _))
                {
                    // 队列中还有待处理请求的话,重置响应计数
                    _remainingResponseCount = 2;
                }
            }
            // 缓存未处理完的半条响应
            state.sb.Clear();
            state.sb.Append(receivedContent);
            // 继续挂起接收等待下一条数据
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        else
        {
            // 服务器主动断开连接
            if (state.sb.Length > 1)
            {
                Console.WriteLine($"服务器断开前最后返回内容:{state.sb.ToString()}");
            }
            client.Close();
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

4. 适配发送回调逻辑

发送成功后初始化对应响应计数:

private static void SendCallback(IAsyncResult ar)
{
    try
    {
        Socket client = (Socket)ar.AsyncState;
        int bytesSent = client.EndSend(ar);
        Console.WriteLine("已发送 {0} 字节到服务器", bytesSent);
        // 如果当前没有等待的响应,设置当前请求需要接收2条响应
        if(_remainingResponseCount == 0)
        {
            _remainingResponseCount = 2;
        }
        sendDone.Set();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

注意:如果你的服务器响应不是以\r\n作为单条结束标识,需要根据实际的通信协议调整响应分割规则,保证能正确拆分出每一条独立响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 10:30:00