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

