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

Java多并发TCP连接出现Connection Refused问题的原因咨询

Java多并发TCP连接出现Connection Refused问题的原因咨询

我最近在Java里尝试实现多并发TCP连接,设置250个并发连接时,部分请求居然收到了Connection Refused的错误,这让我很惊讶——毕竟才250个连接,而大型Web应用明明能处理多得多的并发量。我甚至在Spring Boot Web应用里做了类似测试,结果也遇到了同样的连接拒绝问题。有没有大佬能帮忙分析下原因?(测试环境:Windows 11 PC)

测试代码

TcpServer.java

public class TcpServer {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8090), 500);
        while (true) {
            var socketChannel = serverSocketChannel.accept();
            System.out.println("client connected: " + socketChannel.getRemoteAddress());
            socketChannel.close();
        }
    }
}

TcpStressTest.java

public class TcpStressTest {
    static AtomicInteger successCount = new AtomicInteger(0);
    static AtomicInteger failureCount = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        // create 10k threads to connect to server
        int N = 250;
        ExecutorService executorService = java.util.concurrent.Executors.newFixedThreadPool(50);
        List<Future<Object>> futures = new java.util.ArrayList<>();
        for (int i = 0; i < N; i++) {
            Future<?> submit = executorService.submit(() -> {
                TcpClient client = new TcpClient();
                int start = client.start();
                if (start == 1) {
                    successCount.incrementAndGet();
                } else {
                    failureCount.incrementAndGet();
                }
            });
            futures.add((Future<Object>) submit);
        }
        for (Future<Object> future : futures) {
            try {
                future.get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("All clients finished");
        System.out.println("Success count: " + successCount.get());
        System.out.println("Failure count: " + failureCount.get());
    }
}

TcpClient.java

public class TcpClient {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 8090;

    public int start() {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new java.net.InetSocketAddress(SERVER_HOST, SERVER_PORT));
            socketChannel.close();
            return 1;
        } catch (java.io.IOException e) {
            System.out.println("[Thread: " + Thread.currentThread().getName() + " Connection failed: " + e.getMessage());
            return 0;
        }
    }
}

可能的原因分析及解决思路

看起来你遇到的这个问题在Windows环境下挺常见的,我整理了几个核心原因和对应的解决方向:

1. Windows TCP临时端口耗尽(最可能的原因)

每个客户端发起TCP连接时,都会占用一个本地临时端口(Windows默认范围是49152-65535,总共约1.6万个,但实际可用的会因为系统保留而更少)。当你测试里的客户端连接建立后立刻关闭,这些端口会进入TIME_WAIT状态——Windows默认这个状态会持续120秒,期间端口无法被复用。短时间内大量创建并销毁连接,会快速耗尽可用的临时端口,导致后续连接请求因为找不到可用端口而被拒绝。

解决建议:

  • 修改Windows注册表调整TCP参数(需要管理员权限,修改后重启生效):
    • 扩大临时端口范围:找到HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters,添加/修改MaxUserPort为65535
    • 缩短TIME_WAIT时长:添加/修改TcpTimedWaitDelay为30(单位:秒)
    • 开启端口复用:添加AllowUserPortRange并设为1

2. 服务端单线程处理瓶颈

你的TcpServer是单线程运行的:在while(true)循环里每次只能accept()一个连接,处理完(这里是直接关闭)才能处理下一个。虽然你设置了backlog为500,但单线程的处理速度远远跟不上250个并发连接的请求速度,导致TCP的全连接队列被快速占满,操作系统会直接拒绝后续的连接请求。

解决建议:

  • 把服务端改成多线程模式,用线程池来处理每个接入的连接,提高处理效率:
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8090), 500);
        // 创建线程池处理连接
        ExecutorService threadPool = Executors.newFixedThreadPool(100);
        while (true) {
            var socketChannel = serverSocketChannel.accept();
            threadPool.submit(() -> {
                try {
                    System.out.println("client connected: " + socketChannel.getRemoteAddress());
                } finally {
                    try {
                        socketChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
    

3. Windows对backlog参数的实际限制

你设置了backlog为500,但Windows系统对这个参数有实际的上限(比如部分版本默认上限是200,不会完全遵循你设置的值)。当实际等待队列达到系统上限后,新的连接请求就会被操作系统拒绝。

解决建议:

  • 可以尝试调大backlog值,但更有效的还是优化服务端的处理能力,避免队列被占满。

4. 客户端线程池的并发压力

你用了newFixedThreadPool(50),但提交了250个任务,这意味着会有200个任务在队列中等待。不过真正的问题还是短时间内大量连接创建导致的端口耗尽,调整线程池大小只能缓解,不能根本解决。

解决建议:

  • 测试时不要频繁创建销毁连接,尝试复用连接;或者延长每个连接的持有时间,避免短时间内耗尽端口资源。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 08:44:33