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

TcpListener与TcpClient连接异常:AcceptTcpClient始终返回null求助

问题分析与解决方案

核心问题

你的代码存在两个关键问题,导致出现“AcceptTcpClient()返回null”的误解(实际上该方法不会返回null,成功时返回有效实例,失败时抛出异常):

1. Pending()与子线程Accept的竞争条件

你在主线程用listener.Pending()检测是否有连接,再启动子线程调用AcceptTcpClient()。但Pending()仅检查连接是否存在,不会“占用”该连接。主线程循环会快速重复执行,在子线程真正调用AcceptTcpClient()之前,主线程可能再次检测到Pending()为true,从而启动另一个子线程。此时第一个子线程的AcceptTcpClient()会拿到连接,第二个子线程的AcceptTcpClient()则会阻塞等待新连接,造成“无返回”的假象。

2. 客户端未关闭流导致服务端阻塞

客户端发送数据后,没有关闭NetworkStream或TcpClient,服务端的streamReader.ReadToEnd()会一直等待流的结束信号,导致控制台无输出,让你误以为Accept操作未成功。

修复后的服务端代码

去掉Pending()轮询,直接利用AcceptTcpClient()的阻塞特性处理连接,避免竞争:

public void StartListener()
{
    System.Net.Sockets.TcpListener listener = new(
        IPAddress.Parse("127.0.0.1"),
        15001);
        
    listener.Start();
    try
    {
        while (listen)
        {
            // AcceptTcpClient会阻塞直到有连接,无需轮询Pending
            TcpClient tcpClient = listener.AcceptTcpClient();
            // 启动子线程处理连接
            Thread thread = new Thread(() =>
            {
                using (tcpClient)
                using (NetworkStream networkStream = tcpClient.GetStream())
                using (StreamReader streamReader = new StreamReader(networkStream))
                {
                    string message = streamReader.ReadToEnd();
                    Console.WriteLine("Message: " + message.Length + " bytes");
                }
            });
            thread.Start();
        }
    }
    catch (SocketException se)
    {
        Console.WriteLine($"{se.Message} ({se.ErrorCode})");
        throw;
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
    finally
    {
        listener.Stop();
    }
}

修复后的客户端代码

发送数据后关闭流和客户端,让服务端知晓数据传输完成:

public void StartTcpClient()
{
    try
    {
        using (System.Net.Sockets.TcpClient tcpClient = new())
        {
            tcpClient.Connect("127.0.0.1", 15001);

            using (NetworkStream networkStream = tcpClient.GetStream())
            {
                byte[] message = "This is an example."u8.ToArray();
                networkStream.Write(message, 0, message.Length);
                // 发送结束信号,告知服务端无更多数据
                networkStream.Flush();
                tcpClient.Client.Shutdown(SocketShutdown.Send);
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

额外说明

  • 避免手动轮询Pending(),AcceptTcpClient()本身是阻塞式的,会自动等待新连接,代码更简洁且无竞争问题。
  • 全程使用using语句确保资源正确释放,无论是服务端还是客户端。
  • 客户端发送完数据后调用SocketShutdown.Send,可以明确告知服务端数据传输结束,让ReadToEnd()正常返回。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:12:33