直接抛BindException,是IOException的子类,典型错误为“java.net.BindException: Address already in use”,源于端口被其他进程占用或权限不足(如非root用户绑定1–1023端口)。

ServerSocket 构造时端口被占用会抛什么异常
直接抛 BindException,属于 IOException 的子类,典型错误信息是:java.net.BindException: Address already in use。这不是代码逻辑问题,而是操作系统层面的资源冲突——端口正被其他进程(比如另一个 Java 进程、nginx、python -m http.server,甚至没彻底退出的 zombie 进程)占着。
实操建议:
- 启动前先查:Linux/macOS 用
lsof -i :8080或netstat -an | grep 8080;Windows 用netstat -ano | findstr :8080 - 代码里别只 catch
IOException,要显式捕获BindException,否则掩盖真实原因 - 避免硬编码端口,改用配置文件或
System.getProperty("server.port"),方便测试时快速切换
accept() 阻塞期间能否响应中断
不能靠 Thread.interrupt() 直接唤醒,必须配合 serverSocket.close() 才能打破阻塞——调用 close 后,accept() 立即抛出 SocketException: Socket closed。
常见错误现象:线程已调用 interrupt(),但仍在 accept() 处卡死,因为 socket 没关。
实操建议:
- 关闭服务时,**先调用
serverSocket.close(),再中断线程或清理资源** - 在
accept()循环外加判断:if (serverSocket.isClosed()) break;,防止 close 后还继续调用 accept - 别依赖
Thread.interrupted()控制 accept 退出,它对阻塞 I/O 无效
绑定 0.0.0.0 和 127.0.0.1 的区别
new ServerSocket(8080) 默认绑定 0.0.0.0,表示接受所有网卡(包括公网 IP)的连接;显式写成 new ServerSocket(8080, 50, InetAddress.getByName("127.0.0.1")) 则只响应本地回环请求,外部机器连不上。
使用场景:
- 开发调试用
127.0.0.1更安全,避免误暴露服务 - 生产部署若需外网访问,必须确保绑定的是
0.0.0.0或具体公网 IP,且系统防火墙和云平台安全组已放行该端口 - Docker 容器内
localhost指向容器自身,不等于宿主机,此时必须用0.0.0.0才能被外部访问
backlog 参数的实际影响
ServerSocket(int port, int backlog) 中的 backlog 控制的是“已完成三次握手、等待 accept() 取走”的连接队列长度,不是最大并发数。Linux 默认是 50,超过后新连接会被内核直接拒绝(客户端收到 RST 包,而不是超时)。
实操建议:
- 高并发短连接场景(如 HTTP API),
backlog设为 100–200 更稳妥;长连接(如 WebSocket)可保持默认 - 不要指望靠增大
backlog解决性能瓶颈,它只是缓冲队列,真正瓶颈在业务线程池或 I/O 能力 - 某些旧版 JVM 在 Windows 上对
backlog值有截断(如 max 200),实测时注意验证
实际监听逻辑中,最易被忽略的是:**close() 必须在 accept() 阻塞前完成,且不能依赖中断信号单独触发退出**。很多服务启停异常、端口残留、连接堆积,根源都在这个顺序和判断上。











