端口被占导致“address already in use”时,应先用ss或lsof精准定位进程:ss最快(sudo ss -tulnp | grep :端口),lsof最全(sudo lsof -i :端口);再结合ps和time_wait状态判断是否真占用,最后按需kill、换端口或启用so_reuseaddr预防。

遇到服务启动失败、提示“Address already in use”,基本就是端口被占了。关键不是立刻杀进程,而是先弄清谁在用、为什么在用、能不能动。
快速定位哪个进程占着端口
别猜,直接查。推荐优先用 ss 或 lsof:
-
ss 最快:运行
sudo ss -tulnp | grep :8080(把 8080 换成你实际的端口号),输出里带users:(("xxx",pid=1234,fd=...))就是进程名和 PID -
lsof 最全:运行
sudo lsof -i :8080,能直接看到 COMMAND、PID、USER、状态,一目了然 - netstat 也能用,但新系统可能没装:运行
sudo netstat -tulnp | grep :8080
判断是真占用还是 TIME_WAIT 残留
拿到 PID 后,别急着 kill:
- 运行
ps -p 1234(换成你的 PID),如果显示进程状态是R或S,说明它确实在跑,得评估要不要停 - 如果
ps查不到进程,但ss -ant | grep :8080还能看到TIME_WAIT状态,那就是 TCP 协议机制导致的“假占用”——端口其实空闲,只是内核还没彻底释放,默认卡 60 秒
针对性处理:按情况选方案
根据上一步判断结果操作:
- 确认是无关进程(比如测试残留的 python 脚本):执行
sudo kill -9 1234强制终止 - 发现是必须保留的服务(如 nginx 占 80、mysql 占 3306):改你自己的服务配置,换一个空闲端口,比如从 8080 改成 8081,再重启
- 纯 TIME_WAIT 残留:在代码里监听 socket 前加一行
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));,下次 bind 就能跳过等待直接复用
预防下次再卡住
光救火不行,日常注意几件事:
- 服务退出前确保调用
close()或shutdown(),避免崩溃留下僵死 socket - 开发和调试阶段,监听 socket 默认启用
SO_REUSEADDR,几乎零成本,一劳永逸 - 高频短连接场景下,可适当调小
/proc/sys/net/ipv4/tcp_fin_timeout(不建议低于 30),或谨慎开启tcp_tw_reuse











