检测是否支持 IPv6,OS-不可知,没有外部程序?
Detect if IPv6 is supported, OS-agnostic, no external program?
有没有一种方法可以检测系统是否支持 IPv6,而无需以 OS 不可知的方式使用外部程序 和 ?
我在这里和整个 Internet 上到处搜索,似乎几乎所有提供的解决方案都依赖于访问 /proc
(在 Windows 和 MacOS 上不可用) 或 运行 个外部程序。
我能想到的最好的是:
import errno
import socket
def has_ip6():
try:
socket.create_connection(("::1", 0))
except OSError as e:
if e.errno == errno.EADDRNOTAVAIL:
return False
if e.errno == errno.ECONNREFUSED;
return True
raise
有没有更好的方法?
编辑:不要使用socket.has_ipv6
;请查看@pepoluan 自己的回答!
socket模块包含常量socket.has_ipv6,专门用来表示是否支持IPv6。
尽管@averresen 的回答不正确,但它确实引导我找到了 https://github.com/urllib3/urllib3/pull/611#issuecomment-100954017 中指定的正确答案:
def _is_ipv6_enabled():
"""Check whether IPv6 is enabled on this host."""
if socket.has_ipv6:
sock = None
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind((HOSTv6, 0))
return True
except OSError:
pass
finally:
if sock:
sock.close()
return False
所以基本上我做的已经走对了路,我只需要在开头加一个防御if not socket.has_ipv6: return False
即可。
编辑 1:
这就是我最终得到的:
import socket
import errno
# On Windows, the E* constants will use the WSAE* values
# So no need to hardcode an opaque integer in the sets.
_ADDR_NOT_AVAIL = {errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT}
_ADDR_IN_USE = {errno.EADDRINUSE}
def system_has_ipv6() -> bool:
if not has_ipv6:
return False
try:
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
sock.bind(("::1", 0))
return True
except OSError as e:
if e.errno in _ADDR_NOT_AVAIL:
return False
if e.errno in _ADDR_IN_USE:
# This point shouldn't ever be reached. But just in case...
return True
# Other errors should be inspected
raise
编辑 2:
我将 errno.EAFNOSUPPORT
添加到 _ADDR_NOT_AVAIL
集。 EADDRNOTAVAIL
是 IPv6 modules/drivers 加载但禁用时的错误号,EAFNOSUPPORT
是 IPv6 modules/drivers 根本未加载时的错误号。
有没有一种方法可以检测系统是否支持 IPv6,而无需以 OS 不可知的方式使用外部程序 和 ?
我在这里和整个 Internet 上到处搜索,似乎几乎所有提供的解决方案都依赖于访问 /proc
(在 Windows 和 MacOS 上不可用) 或 运行 个外部程序。
我能想到的最好的是:
import errno
import socket
def has_ip6():
try:
socket.create_connection(("::1", 0))
except OSError as e:
if e.errno == errno.EADDRNOTAVAIL:
return False
if e.errno == errno.ECONNREFUSED;
return True
raise
有没有更好的方法?
编辑:不要使用socket.has_ipv6
;请查看@pepoluan 自己的回答!
socket模块包含常量socket.has_ipv6,专门用来表示是否支持IPv6。
尽管@averresen 的回答不正确,但它确实引导我找到了 https://github.com/urllib3/urllib3/pull/611#issuecomment-100954017 中指定的正确答案:
def _is_ipv6_enabled():
"""Check whether IPv6 is enabled on this host."""
if socket.has_ipv6:
sock = None
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind((HOSTv6, 0))
return True
except OSError:
pass
finally:
if sock:
sock.close()
return False
所以基本上我做的已经走对了路,我只需要在开头加一个防御if not socket.has_ipv6: return False
即可。
编辑 1:
这就是我最终得到的:
import socket
import errno
# On Windows, the E* constants will use the WSAE* values
# So no need to hardcode an opaque integer in the sets.
_ADDR_NOT_AVAIL = {errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT}
_ADDR_IN_USE = {errno.EADDRINUSE}
def system_has_ipv6() -> bool:
if not has_ipv6:
return False
try:
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
sock.bind(("::1", 0))
return True
except OSError as e:
if e.errno in _ADDR_NOT_AVAIL:
return False
if e.errno in _ADDR_IN_USE:
# This point shouldn't ever be reached. But just in case...
return True
# Other errors should be inspected
raise
编辑 2:
我将 errno.EAFNOSUPPORT
添加到 _ADDR_NOT_AVAIL
集。 EADDRNOTAVAIL
是 IPv6 modules/drivers 加载但禁用时的错误号,EAFNOSUPPORT
是 IPv6 modules/drivers 根本未加载时的错误号。