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

C# TCP监听器高并发连接0.5%错误率的排查与优化方法

问题:TCP监听器高并发下出现连接拒绝错误(0.5%错误率)

我编写了一个简单的TCP监听器代码,使用Apache JMeter以500线程进行负载测试时,出现0.5%的错误率。错误信息显示:Response code: 500,Response message: java.net.ConnectException: Connection refused: connect。需要排查错误原因并优化该监听器解决问题。

代码如下:

static async Task Main(string[] args)
{
    
    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    int port = 7777;

    // Create a TCP listener
    TcpListener listener = new TcpListener(ipAddress, port);
    listener.Start();
    Console.WriteLine("Server started. Waiting for connections...");

    try
    {
        while (true)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
        

            // Handle the client asynchronously
            _ = HandleClientAsync(client);
        }
    }
    finally
    {
        listener.Stop();
    }
}
   

static async Task HandleClientAsync(TcpClient client)
{
    try
    {
        NetworkStream stream = client.GetStream();

        byte[] buffer = new byte[1024];
        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
        string requestMessage = Encoding.ASCII.GetString(buffer, 0, bytesRead);
       // Console.WriteLine("Request message from client: " + requestMessage);

        // Response message
        byte[] responseData = Encoding.ASCII.GetBytes("test response");

        //Thread.Sleep(50);
        // Send the response to the client asynchronously
        await stream.WriteAsync(responseData, 0, responseData.Length);
        //Console.WriteLine("Response sent to client.");

    }
    catch (Exception ex)
    {
        Console.WriteLine("Error: " + ex.Message);
    }
    finally
    {
        // Close the connection
        client.Close();
        //Console.WriteLine("Client disconnected.");
    }

}

附测试结果截图:测试结果截图


排查原因

  • TCP连接等待队列不足:Windows默认的TCP半连接队列(backlog)容量较小(通常默认50),当500线程的并发请求超过队列承载上限时,新的连接请求会被系统直接拒绝。
  • 资源释放不规范:手动调用client.Close()可能存在资源释放不彻底的情况,导致连接资源积压,影响新连接建立。
  • 线程池扩容延迟:异步操作依赖.NET线程池,高并发场景下线程池默认的扩容机制可能跟不上请求速度,导致AcceptTcpClientAsync无法及时处理新连接。
  • 系统TCP参数限制:系统层面的TCP连接相关参数(如MaxConnBacklog)未调整,无法支持高并发连接请求。

优化方案

1. 增大TCP连接等待队列

修改TcpListener.Start()方法,显式指定更大的backlog值,适配500线程的并发需求:

listener.Start(1000); // 设置队列大小为1000,可根据实际并发量调整

同时调整Windows系统TCP参数(管理员权限执行命令提示符):

netsh int tcp set global maxconnbacklog=2000
netsh int tcp set global synattackprotect=disabled

修改后需重启系统生效,参数值可根据硬件配置进一步调整。

2. 规范资源释放逻辑

使用using语句自动管理TcpClient和NetworkStream的生命周期,替代手动Close(),确保资源被及时释放:

static async Task HandleClientAsync(TcpClient client)
{
    using (client)
    using (NetworkStream stream = client.GetStream())
    {
        byte[] buffer = new byte[1024];
        int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
        string requestMessage = Encoding.ASCII.GetString(buffer, 0, bytesRead);

        byte[] responseData = Encoding.ASCII.GetBytes("test response");
        await stream.WriteAsync(responseData, 0, responseData.Length);
        await stream.FlushAsync(); // 确保响应数据完全发送
    }
}

3. 优化线程池配置

在程序启动时设置线程池最小线程数,避免高并发下线程池扩容延迟:

static async Task Main(string[] args)
{
    // 配置线程池最小工作线程和IO线程数,适配高并发场景
    ThreadPool.SetMinThreads(200, 200);

    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    int port = 7777;
    TcpListener listener = new TcpListener(ipAddress, port);
    listener.Start(1000);
    Console.WriteLine("Server started. Waiting for connections...");

    try
    {
        while (true)
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            _ = HandleClientAsync(client);
        }
    }
    finally
    {
        listener.Stop();
    }
}

4. 添加连接监控日志

在关键节点添加日志,便于定位连接失败的具体场景:

static async Task HandleClientAsync(TcpClient client)
{
    var clientAddr = client.Client.RemoteEndPoint.ToString();
    try
    {
        using (client)
        using (NetworkStream stream = client.GetStream())
        {
            Console.WriteLine($"新连接建立:{clientAddr}");
            byte[] buffer = new byte[1024];
            int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
            
            byte[] responseData = Encoding.ASCII.GetBytes("test response");
            await stream.WriteAsync(responseData, 0, responseData.Length);
            await stream.FlushAsync();
            Console.WriteLine($"响应已发送:{clientAddr}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"连接处理出错 {clientAddr}:{ex.Message}");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:50:22