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

频繁创建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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:01:10