han*_*ers 5 python sockets linux tcp ipv6
我试图使用IPv6地址绑定python tcp套接字。
self.__addr = ('fe80::224:d7ff:fe9d:9800', 5050)
self.__type = socket.AF_INTE6
self.__sock = socket.socket(self.__type, socket.SOCK_STREAM)
for family, _, _, _, sockaddr in socket.getaddrinfo( self.__addr[0], self.__addr[1], 0, 0, socket.SOL_TCP ):
if family == self.__type:
self.__addr = sockaddr
break
self.__sock.bind( self.__addr )
self.__sock.listen(1)
Run Code Online (Sandbox Code Playgroud)
如其他解决方案中所述,我使用了来自socket.getaddrinfo()的结果,但始终会收到此错误:
self.__sock.bind( self.__addr )
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 22] Invalid argument
Run Code Online (Sandbox Code Playgroud)
这是我的网络接口的ifconfig结果
wlan0 Link encap:Ethernet Hardware Adresse 00:24:d7:9d:98:00
inet Adresse:192.168.0.103 Bcast:192.168.0.255 Maske:255.255.255.0
inet6-Adresse: fe80::224:d7ff:fe9d:9800/64
Run Code Online (Sandbox Code Playgroud)
知道为什么会发生此错误吗?
通常网络前缀不会重叠,并且每个 IP 地址仅在单个接口上使用。但是,对于本地链路,fe80::/10在每个启用 IPv6 的网络接口上使用(相同)前缀 ( )。这意味着系统无法仅根据链路本地地址来确定要侦听的网络接口。您必须自己指定接口。
%当以字符串表示法编写地址时,您可以通过将接口 id 附加到 IPv6 地址来实现。正如 glglgl 所示,这可能是例如fe80::224:d7ff:fe9d:9800%wlan0。接口名称取决于您所在的系统。我的 OS X 机器有接口en0和en1,我的 Linux 机器有eth0,在 Windows 机器上接口名称将是一个整数。
在套接字函数中,使用范围 ID 指定接口。这是地址元组的一部分。在您的示例中,您使用('fe80::224:d7ff:fe9d:9800', 5050). 这没问题,因为对于 IPv6,最后两个元素可以省略。完整的地址元组例如('fe80::224:d7ff:fe9d:9800', 5050, 0, 4)是4scope-id。
您可以使用一个小脚本来测试它,例如:
import socket
addrs = [('fe80::cafe:1%en0', 5050),
('fe80::cafe:1%en1', 5050)]
for addr in addrs:
print('Original addr: {}'.format(addr))
for res in socket.getaddrinfo(addr[0], addr[1], socket.AF_INET6,
socket.SOCK_STREAM, socket.SOL_TCP):
af, socktype, proto, canonname, sa = res
print('Full addr: {}'.format(sa))
print('')
Run Code Online (Sandbox Code Playgroud)
在我的系统上运行此脚本显示:
Original addr: ('fe80::cafe:1%en0', 5050)
Full addr: ('fe80::cafe:1%en0', 5050, 0, 4)
Original addr: ('fe80::cafe:1%en1', 5050)
Full addr: ('fe80::cafe:1%en1', 5050, 0, 5)
Run Code Online (Sandbox Code Playgroud)
%套接字绑定不再使用 后面的部分,它依赖于作用域 ID。
这确实意味着以下bind调用会产生相同的结果:
s = socket.socket(af, socktype, proto)
s.bind(('fe80::cafe:1', 5050, 0, 4))
s.bind(('fe80::cafe:1%en0', 5050, 0, 4))
s.bind(('fe80::cafe:1%bla', 5050, 0, 4))
Run Code Online (Sandbox Code Playgroud)
最好使用您从中返回的原始值getaddrinfo。依赖于这种未定义的行为并不是一个好主意。像这样的简单循环应该效果最好:
addr = ('fe80::224:d7ff:fe9d:9800%wlan0', 5050)
s = None
for res in socket.getaddrinfo(addr[0], addr[1], socket.AF_INET6,
socket.SOCK_STREAM, socket.SOL_TCP):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
s.bind(sa)
s.listen(1)
except socket.error:
if s is not None:
s.close()
s = None
if s is None:
print('Socket opening/binding failed')
etc.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1737 次 |
| 最近记录: |