oserror: [errno 98] address already in use本质是端口被残留进程或time_wait状态占用,非代码错误;解决方法包括:1.用lsof或netstat查杀占用进程;2.在bind前调用setsockopt(sol_socket, so_reuseaddr, 1)允许地址复用。
![python中如何修复socket编程产生的oserror: [errno 98] address already in use?](https://img.php.cn/upload/article/000/969/633/178354866341570.png?x-oss-process=image/resize,p_40)
这个问题本质是端口被残留进程占着,不是代码写错了,重启程序前必须先释放端口。
为什么会出现 OSError: [Errno 98] Address already in use?
Python 的 socket.bind() 失败,因为操作系统还没回收上一次连接占用的端口。常见于:程序异常退出(没调 close())、Ctrl+C 中断后立即重跑、或快速重启服务。
Linux/macOS 默认启用 TIME_WAIT 状态(持续约 60 秒),期间端口不可复用;Windows 表现类似,但机制略有差异。
- 不是防火墙或权限问题(那些会报
Permission denied或Address not available) - 不是端口被其他软件长期占用(比如 80 被 nginx 占了),而是你自己刚用过的端口还没“松手”
-
netstat -tuln | grep :<em>PORT</em>或lsof -i :<em>PORT</em>查到的 PID 往往就是你上次跑的 Python 进程
最稳妥的修复方式:设置 SO_REUSEADDR socket 选项
在 bind() 前加一行,告诉操作系统:“允许重用处于 TIME_WAIT 状态的地址”。这是标准做法,几乎所有 TCP 服务器都该加。
import socket
<p>sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # ← 关键这一行
sock.bind(('localhost', 8080))
sock.listen(5)
</p>
- Windows、Linux、macOS 全平台有效
- 只对
bind()生效,不影响已建立连接 - 不会绕过端口冲突检测(比如真有别的进程在监听同一端口,仍会报错)
- 某些旧系统或特殊内核配置下需配合
SO_REUSEPORT(Linux 3.9+),但绝大多数情况SO_REUSEADDR就够了
开发时快速清理残留端口的方法
别总靠等 60 秒,手动杀掉旧进程更直接:
- Linux/macOS:
lsof -i :8080找 PID,再kill -9 PID;或者一键lsof -ti:8080 | xargs kill -9 - Windows:
netstat -ano | findstr :8080找 PID,再taskkill /PID <em>PID</em> /F - Python 脚本里加异常兜底(仅限开发):
try...except OSError as e:判断e.errno == 98后 sleep 1 秒再重试——但这只是掩耳盗铃,不解决根本
容易被忽略的细节:SO_REUSEADDR 不等于“自动重试”
它只是放宽 bind 限制,不代表你的程序能跳过错误继续跑。如果端口真被其他进程占着(比如另一个 Python 实例还在运行),SO_REUSEADDR 也救不了你。
- 务必确认没有后台僵尸进程:
ps aux | grep python或任务管理器查一遍 - IDE(如 PyCharm)调试中断后常留子进程,关掉 IDE 再试更干净
- 用
localhost和127.0.0.1绑定效果一致,但别混用(比如 bindlocalhost,却用curl 127.0.0.1:8080测试失败——其实是 DNS 解析或 IPv6 优先级问题,和 Errno 98 无关)
真正要命的不是加不加 SO_REUSEADDR,而是加完就以为万事大吉,结果发现端口被别的服务占着,或者脚本反复 fork 出新进程却没清理旧的——这时候看 netstat 比看代码更快。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











