频繁创建Socket连接后客户端抛出java.net.BindException问题排查
问题分析:短时间创建大量Socket连接后抛出
java.net.BindException 问题背景
运行平台:Windows 10 Enterprise、JDK 17
客户端在循环建立数千次Socket连接后抛出java.net.BindException,但如果每次循环执行间添加10ms休眠,则可持续正常运行。
客户端代码
import java.io.*; import java.net.Socket; public class Client { public static void main(final String[] args) throws IOException { final byte[] readBuffer = new byte[8192]; while (true) { try ( final Socket socket = new Socket("localhost", 1972); final InputStream ist = socket.getInputStream(); final OutputStream ost = socket.getOutputStream(); final ByteArrayOutputStream istBAOS = new ByteArrayOutputStream()) { ost.write("Hello!".getBytes()); socket.shutdownOutput(); int readCount; while((readCount = ist.read(readBuffer)) != -1) { istBAOS.write(readBuffer, 0, readCount); } final byte[] istBytes = istBAOS.toByteArray(); socket.shutdownInput(); System.out.println("Client.: " + socket + " <- " + new String(istBytes)); } } } }
服务端代码
import java.io.*; import java.net.*; public class Server { public static void main(final String[] args) throws IOException { final byte[] readBuffer = new byte[8192]; try ( final ServerSocket server = new ServerSocket(1972)) { while (true) { try ( final Socket socket = server.accept(); final InputStream ist = socket.getInputStream(); final OutputStream ost = socket.getOutputStream(); final ByteArrayOutputStream istBAOS = new ByteArrayOutputStream()) { int readCount; while((readCount = ist.read(readBuffer)) != -1) { istBAOS.write(readBuffer, 0, readCount); } final byte[] istBytes = istBAOS.toByteArray(); socket.shutdownInput(); ost.write(istBytes); socket.shutdownOutput(); } catch (final IOException e) { e.printStackTrace(); } // try {Thread.sleep(10);} catch (final InterruptedException e) {} } } } }
原因解释
这个问题的核心是Windows系统下TCP连接的TIME_WAIT状态导致临时端口耗尽:
- 客户端每次创建Socket连接时,系统会分配一个临时端口(Windows默认临时端口范围是49152-65535,共约16384个)。
- 当连接关闭后,该端口会进入TIME_WAIT状态(Windows默认时长为240秒),这段时间内端口无法被重新分配。
- 无休眠的客户端会在短时间内快速创建并关闭大量连接,迅速耗尽所有可用临时端口,导致后续创建连接时无法获取新端口,抛出
BindException。 - 添加10ms休眠后,连接创建速度放缓,让处于TIME_WAIT状态的端口有足够时间释放回端口池,因此不会出现端口耗尽问题。
解决方案
1. 调整Windows TCP参数(需管理员权限)
- 缩短TIME_WAIT时长:修改注册表项
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters中的TcpTimedWaitDelay,设置为更小的值(比如30,单位秒),重启系统生效。 - 扩大临时端口范围:修改同一路径下的
MaxUserPort,设置为更大的值(比如65535),增加可用临时端口数量。
2. 优化客户端连接复用
如果业务允许,尽量复用Socket连接,而非每次请求都创建新连接,从根本上减少端口占用。
3. 调整Socket选项(有限作用)
客户端可尝试设置SO_REUSEADDR选项,但该选项主要针对服务端绑定端口场景,对客户端临时端口复用效果有限,代码示例:
Socket socket = new Socket(); socket.setReuseAddress(true); socket.connect(new InetSocketAddress("localhost", 1972));
内容的提问来源于stack exchange,提问作者Dave The Dane
相关产品推荐
相关产品推荐

