循环检测IP时出现OSError: [Errno 48] Address already in use问题求助
解决whatismyip包循环调用出现Address already in use的问题
核心原因分析
MacOS下即便设置了SO_REUSEADDR,TCP连接关闭后的TIME_WAIT状态仍会占用端口一段时间,而whatismyip的部分实现未正确复用端口或处理连接关闭逻辑,导致循环调用时端口被快速耗尽。你的最小复现示例仅出现警告,是因为调用频率、资源占用量未达到触发报错的阈值,但实际业务代码的调用场景更密集,因此触发了端口占用错误。
可行解决办法
1. 手动配置Socket参数,启用端口复用
MacOS下仅靠SO_REUSEADDR不足以彻底解决问题,需同时启用SO_REUSEPORT,并绑定随机可用端口而非固定端口:
from whatismyip import whatismyipv4 import socket def get_my_ip(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 启用地址复用 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 启用端口复用(MacOS关键配置) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) # 绑定到0.0.0.0的随机可用端口 sock.bind(('0.0.0.0', 0)) # 传递自定义Socket给whatismyipv4 return whatismyipv4(sock=sock)
2. 显式关闭Socket,强制释放资源
每次调用后主动关闭Socket,避免资源泄漏累积:
def get_my_ip_safe(): ip = None sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) sock.bind(('0.0.0.0', 0)) ip = whatismyipv4(sock=sock) finally: # 先关闭读写流,再释放Socket sock.shutdown(socket.SHUT_RDWR) sock.close() return ip
3. 临时调整系统TCP参数,缩短端口占用时间
在终端执行以下命令,缩短TIME_WAIT状态的持续时间(重启后失效):
sudo sysctl -w net.inet.tcp.msl=1000
注:默认
msl为15000毫秒,改为1000毫秒会让端口更快释放,但可能对TCP连接稳定性有轻微影响,仅建议在测试或临时场景使用。
4. 替换为无端口绑定的IP检测方式
如果whatismyip包的问题无法彻底解决,直接用HTTP请求调用公开IP检测接口,完全避开端口绑定逻辑:
import requests def get_public_ip(): try: return requests.get('https://api.ipify.org', timeout=5).text except requests.exceptions.RequestException: return requests.get('https://icanhazip.com', timeout=5).text.strip()
为什么重试机制无效?
端口处于TIME_WAIT状态时,系统短时间内不会释放该端口,直接重试同一个端口绑定操作必然失败。需要更换端口、等待端口释放,或改用无端口绑定的检测方式。
内容的提问来源于stack exchange,提问作者Jossy
相关产品推荐
相关产品推荐

