Python端口扫描如何仅检测IPv4端口 解决AF_INET误报IPv6占用问题
问题原因
多数主流操作系统默认关闭了IPv6套接字的IPV6_V6ONLY参数,此时绑定到::+端口的IPv6套接字会同时占用对应端口的IPv4、IPv6双栈入口,导致使用AF_INET(IPv4)套接字绑定0.0.0.0时触发端口占用报错,无法区分是IPv4本身被占还是被IPv6关联占用。
解决方案
通过二次校验逻辑即可实现准确的IPv4端口占用检测,无需引入第三方依赖,调整后代码如下:
import socket import errno def is_ipv4_port_available(port): # 尝试绑定IPv4通配地址 s_ipv4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s_ipv4.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s_ipv4.bind(("0.0.0.0", port)) s_ipv4.close() return True except socket.error as e: s_ipv4.close() if e.errno != errno.EADDRINUSE: return False # 触发端口占用报错时,校验是否为IPv6独占导致的误报 s_ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) try: s_ipv6.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1) s_ipv6.bind(("::", port)) s_ipv6.close() # IPv6绑定成功,说明原报错为IPv6占用导致,IPv4端口实际可用 return True except socket.error: s_ipv6.close() # IPv6也绑定失败,说明端口确实被IPv4服务占用 return False # 测试调用 port = 80 if is_ipv4_port_available(port): print(f"IPv4端口{port}可用") else: print(f"IPv4端口{port}已被占用")
逻辑说明
- 第一次绑定IPv4通配地址成功,直接判定端口可用
- 第一次绑定报端口占用错误时,创建开启
IPV6_V6ONLY参数的IPv6套接字尝试绑定同端口- 若IPv6绑定成功:说明之前的报错是未开启
IPV6_V6ONLY的IPv6套接字占用端口导致的误判,IPv4侧实际可用 - 若IPv6绑定也报端口占用:说明端口确实已经被IPv4服务占用
- 若IPv6绑定成功:说明之前的报错是未开启
- 代码中加入
SO_REUSEADDR参数是为了规避处于TIME_WAIT状态的连接导致的误判,不需要可直接删除
内容的提问来源于stack exchange,提问作者Kryptic Coconut
相关产品推荐
相关产品推荐

