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

TCP Socket监听仅首次可用,重启客户端后连接被拒绝求助

问题根源与修正方案

核心错误:服务器仅处理一次连接即停止监听

你的服务器代码在处理完第一个客户端的消息交互后就会退出StartServer方法,导致监听Socket被销毁,端口不再接受新连接,这是第二次客户端连接被拒绝的直接原因。

具体问题点:

  • 监听Socket(listener)被using包裹,StartServer方法执行完毕时,listener会自动被Dispose,停止监听端口。
  • 代码中仅调用一次listener.AcceptAsync()处理单个客户端,处理完成后直接返回true,没有进入下一轮监听循环。

修正步骤

1. 修改服务器代码,实现持续监听

调整服务器逻辑,让其在处理完一个客户端后继续等待下一个连接,同时调整listener的生命周期,确保服务器运行期间监听始终有效。

修正后的服务器代码示例:

public async Task StartServer()
{
    IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
    IPAddress ipAddress = ipHostInfo.AddressList[0];
    IPEndPoint ipEndPoint = new(ipAddress, 8888);

    Socket listener = new(
        ipEndPoint.AddressFamily,
        SocketType.Stream,
        ProtocolType.Tcp);

    try
    {
        listener.Bind(ipEndPoint);
        listener.Listen(100);
        AddLogText("服务器已启动,等待客户端连接...");

        // 持续监听新客户端连接
        while (true)
        {
            Socket client = await listener.AcceptAsync();
            AddLogText("新客户端已连接");

            // 异步处理客户端消息,避免阻塞监听逻辑
            _ = HandleClientAsync(client);
        }
    }
    catch (Exception ex)
    {
        AddLogText($"服务器异常: {ex.Message}");
        listener.Dispose();
    }
}

// 单独提取客户端消息处理逻辑
private async Task HandleClientAsync(Socket client)
{
    try
    {
        while (true)
        {
            var buffer = new byte[1_024];
            var received = await client.ReceiveAsync(buffer, SocketFlags.None);
            if (received == 0) break; // 客户端主动断开连接

            var response = Encoding.UTF8.GetString(buffer, 0, received);
            var eom = "<|EOM|>";

            if (response.IndexOf(eom) > -1)
            {
                AddLogText($"Socket server received message: \"{response.Replace(eom, "")}\"");
                var ackMessage = "Hallo Client!<|ACK|>";
                var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
                await client.SendAsync(echoBytes, 0);
                AddLogText($"Socket server sent acknowledgment: \"{ackMessage}\"");
                break;
            }
        }
    }
    catch (Exception ex)
    {
        AddLogText($"客户端处理异常: {ex.Message}");
    }
    finally
    {
        client.Shutdown(SocketShutdown.Both);
        client.Close();
        AddLogText("客户端连接已关闭");
    }
}

2. 客户端代码补充:显式关闭连接

客户端当前代码中using包裹的Socket会在方法结束时自动释放,但显式关闭连接能更规范地释放资源:

private async Task<bool> StartClient()
{
    IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
    IPAddress ipAddress = ipHostInfo.AddressList[0];
    IPEndPoint ipEndPoint = new(ipAddress, 8888);

    using Socket client = new(
        ipEndPoint.AddressFamily,
        SocketType.Stream,
        ProtocolType.Tcp);

    try
    {
        await client.ConnectAsync(ipEndPoint);
        while (true)
        {
            var message = "Hallo Server?<|EOM|>";
            var messageBytes = Encoding.UTF8.GetBytes(message);
            await client.SendAsync(messageBytes, SocketFlags.None);
            Console.WriteLine($"Socket client sent message: \"{message}\"");
            
            var buffer = new byte[1_024];
            var received = await client.ReceiveAsync(buffer, SocketFlags.None);
            var response = Encoding.UTF8.GetString(buffer, 0, received);
            
            if (response.Contains("<|ACK|>"))
            {
                Console.WriteLine($"Socket client received acknowledgment: \"{response}\"");
                break;
            }
        }
        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"客户端异常: {ex.Message}");
        return false;
    }
    finally
    {
        client.Shutdown(SocketShutdown.Both);
        client.Close();
    }
}

其他排查思路

  • 检查端口状态:用netstat -ano | findstr :8888命令查看端口是否被占用,确认服务器退出后端口是否正常释放。
  • 确保服务器后台运行:在WPF中需用Task.Run启动StartServer,避免主线程阻塞导致服务器进程提前结束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 13:10:28