Python 3 IPv6 多播
Python 3 IPv6 Multicast
我正在尝试为 Python 中的 IPv6 多播通信设计一个简单的 client/server 对。到目前为止,我的代码似乎符合我在网上看到的示例,但我的服务器从未接收到数据。
我在 ip maddr show
和 netstat -g
中看到了订阅。 tcpdump 显示:10:13:36.913546 IP6 (flowlabel 0x77fe8, hlim 5, next-header UDP (17) payload length: 20) **omitted** > ff16::fe.commplex-main: [udp sum ok] UDP, length 12
客户端和服务器连接在同一台交换机上,IPv6单播地址在同一子网中(可以互相ping通)。
服务器
#!/usr/bin/python3
import socket
import struct
local_addr = ::
mcast_addr = "ff16::fe"
mcast_port = 5000
ifn = "eno1"
# Create socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
# Set multicast interface
ifi = socket.if_nametoindex(ifn)
ifis = struct.pack("I", ifi)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
# Set multicast group to join
group = socket.inet_pton(socket.AF_INET6, mcast_addr) + ifis
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
sock_addr = socket.getaddrinfo(local_addr, mcast_port, socket.AF_INET6, socket.SOCK_DGRAM)[0][4]
sock.bind(sock_addr)
cmd = ""
while True:
data, src = sock.recvfrom(1024)
print("From " + str(src) + ": " + data.decode())
客户端
#!/usr/bin/python3
import socket
import struct
message = "Hello world!"
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock_addr = socket.getaddrinfo("ff16::fe", 5000, socket.AF_INET6, socket.SOCK_DGRAM)[0][4]
ttl = struct.pack('i', 5)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl)
sock.sendto(message.encode(), sock_addr)
如有任何意见,我们将不胜感激。
您不能使用 "ff10::
作为 IPv6 多播地址。您在该地址中使用的范围 0
已保留。对于使用标志和范围的 IPv6 多播,有多个 RFC 需要考虑。例如,范围 1
是接口本地范围,发送到具有该范围的组的流量不会离开发送主机上的本地接口。
有关最新范围,请参阅 RFC 7346, IPv6 Multicast Address Scopes:
- Definition of IPv6 Multicast Address Scopes (Updates RFC 4291)
The following table updates the definitions in [RFC4291]:
+------+--------------------------+-------------------------+
| scop | NAME | REFERENCE |
+------+--------------------------+-------------------------+
| 0 | Reserved | [RFC4291], RFC 7346 |
| 1 | Interface-Local scope | [RFC4291], RFC 7346 |
| 2 | Link-Local scope | [RFC4291], RFC 7346 |
| 3 | Realm-Local scope | [RFC4291], RFC 7346 |
| 4 | Admin-Local scope | [RFC4291], RFC 7346 |
| 5 | Site-Local scope | [RFC4291], RFC 7346 |
| 6 | Unassigned | |
| 7 | Unassigned | |
| 8 | Organization-Local scope | [RFC4291], RFC 7346 |
| 9 | Unassigned | |
| A | Unassigned | |
| B | Unassigned | |
| C | Unassigned | |
| D | Unassigned | |
| E | Global scope | [RFC4291], RFC 7346 |
| F | Reserved | [RFC4291], RFC 7346 |
+------+--------------------------+-------------------------+
编辑:
根据您对原始问题的更改,您没有正确计算 UDP 校验和,这对于 IPv4 是可选的,但对于 IPv6 是必需的。
此外,因为您正在构建自己的多播地址(不是 IANA 分配的地址),您还应该返回使用 T
标志作为 1
:
T = 0 indicates a permanently-assigned ("well-known") multicast
address, assigned by the Internet Assigned Numbers Authority (IANA).
T = 1 indicates a non-permanently-assigned ("transient" or
"dynamically" assigned) multicast address.
编辑 2:
顺便说一下,您不能在 IPv6 多播中使用零地址:
Reserved Multicast Addresses:
FF00:0:0:0:0:0:0:0
FF01:0:0:0:0:0:0:0
FF02:0:0:0:0:0:0:0
FF03:0:0:0:0:0:0:0
FF04:0:0:0:0:0:0:0
FF05:0:0:0:0:0:0:0
FF06:0:0:0:0:0:0:0
FF07:0:0:0:0:0:0:0
FF08:0:0:0:0:0:0:0
FF09:0:0:0:0:0:0:0
FF0A:0:0:0:0:0:0:0
FF0B:0:0:0:0:0:0:0
FF0C:0:0:0:0:0:0:0
FF0D:0:0:0:0:0:0:0
FF0E:0:0:0:0:0:0:0
FF0F:0:0:0:0:0:0:0
听起来您真的非常需要在尝试使用 IPv6 多播之前研究 RFC。
除了所有其他好的建议:将服务器上的套接字绑定到 link 本地地址。这将过滤传入的数据包,以便只有具有该目标地址的数据包才能到达您的代码。寻址到多播地址的数据包将被丢弃。尝试绑定到 :: 并确保在继续进行更复杂的操作之前有效。
我还必须在客户端中设置多播接口。客户端和服务器都有一个虚拟接口和一个可操作的 VLAN 感知接口(网络驱动程序的设计我无法进入。我将两者的接口设置为 VLAN 感知接口。
在客户端:
# Set multicast interface
ifi = socket.if_nametoindex(ifn)
ifis = struct.pack("I", ifi)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
我正在尝试为 Python 中的 IPv6 多播通信设计一个简单的 client/server 对。到目前为止,我的代码似乎符合我在网上看到的示例,但我的服务器从未接收到数据。
我在 ip maddr show
和 netstat -g
中看到了订阅。 tcpdump 显示:10:13:36.913546 IP6 (flowlabel 0x77fe8, hlim 5, next-header UDP (17) payload length: 20) **omitted** > ff16::fe.commplex-main: [udp sum ok] UDP, length 12
客户端和服务器连接在同一台交换机上,IPv6单播地址在同一子网中(可以互相ping通)。
服务器
#!/usr/bin/python3
import socket
import struct
local_addr = ::
mcast_addr = "ff16::fe"
mcast_port = 5000
ifn = "eno1"
# Create socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
# Set multicast interface
ifi = socket.if_nametoindex(ifn)
ifis = struct.pack("I", ifi)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
# Set multicast group to join
group = socket.inet_pton(socket.AF_INET6, mcast_addr) + ifis
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
sock_addr = socket.getaddrinfo(local_addr, mcast_port, socket.AF_INET6, socket.SOCK_DGRAM)[0][4]
sock.bind(sock_addr)
cmd = ""
while True:
data, src = sock.recvfrom(1024)
print("From " + str(src) + ": " + data.decode())
客户端
#!/usr/bin/python3
import socket
import struct
message = "Hello world!"
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock_addr = socket.getaddrinfo("ff16::fe", 5000, socket.AF_INET6, socket.SOCK_DGRAM)[0][4]
ttl = struct.pack('i', 5)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl)
sock.sendto(message.encode(), sock_addr)
如有任何意见,我们将不胜感激。
您不能使用 "ff10::
作为 IPv6 多播地址。您在该地址中使用的范围 0
已保留。对于使用标志和范围的 IPv6 多播,有多个 RFC 需要考虑。例如,范围 1
是接口本地范围,发送到具有该范围的组的流量不会离开发送主机上的本地接口。
有关最新范围,请参阅 RFC 7346, IPv6 Multicast Address Scopes:
- Definition of IPv6 Multicast Address Scopes (Updates RFC 4291)
The following table updates the definitions in [RFC4291]:
+------+--------------------------+-------------------------+ | scop | NAME | REFERENCE | +------+--------------------------+-------------------------+ | 0 | Reserved | [RFC4291], RFC 7346 | | 1 | Interface-Local scope | [RFC4291], RFC 7346 | | 2 | Link-Local scope | [RFC4291], RFC 7346 | | 3 | Realm-Local scope | [RFC4291], RFC 7346 | | 4 | Admin-Local scope | [RFC4291], RFC 7346 | | 5 | Site-Local scope | [RFC4291], RFC 7346 | | 6 | Unassigned | | | 7 | Unassigned | | | 8 | Organization-Local scope | [RFC4291], RFC 7346 | | 9 | Unassigned | | | A | Unassigned | | | B | Unassigned | | | C | Unassigned | | | D | Unassigned | | | E | Global scope | [RFC4291], RFC 7346 | | F | Reserved | [RFC4291], RFC 7346 | +------+--------------------------+-------------------------+
编辑:
根据您对原始问题的更改,您没有正确计算 UDP 校验和,这对于 IPv4 是可选的,但对于 IPv6 是必需的。
此外,因为您正在构建自己的多播地址(不是 IANA 分配的地址),您还应该返回使用 T
标志作为 1
:
T = 0 indicates a permanently-assigned ("well-known") multicast address, assigned by the Internet Assigned Numbers Authority (IANA).
T = 1 indicates a non-permanently-assigned ("transient" or "dynamically" assigned) multicast address.
编辑 2:
顺便说一下,您不能在 IPv6 多播中使用零地址:
Reserved Multicast Addresses:
FF00:0:0:0:0:0:0:0
FF01:0:0:0:0:0:0:0
FF02:0:0:0:0:0:0:0
FF03:0:0:0:0:0:0:0
FF04:0:0:0:0:0:0:0
FF05:0:0:0:0:0:0:0
FF06:0:0:0:0:0:0:0
FF07:0:0:0:0:0:0:0
FF08:0:0:0:0:0:0:0
FF09:0:0:0:0:0:0:0
FF0A:0:0:0:0:0:0:0
FF0B:0:0:0:0:0:0:0
FF0C:0:0:0:0:0:0:0
FF0D:0:0:0:0:0:0:0
FF0E:0:0:0:0:0:0:0
FF0F:0:0:0:0:0:0:0
听起来您真的非常需要在尝试使用 IPv6 多播之前研究 RFC。
除了所有其他好的建议:将服务器上的套接字绑定到 link 本地地址。这将过滤传入的数据包,以便只有具有该目标地址的数据包才能到达您的代码。寻址到多播地址的数据包将被丢弃。尝试绑定到 :: 并确保在继续进行更复杂的操作之前有效。
我还必须在客户端中设置多播接口。客户端和服务器都有一个虚拟接口和一个可操作的 VLAN 感知接口(网络驱动程序的设计我无法进入。我将两者的接口设置为 VLAN 感知接口。
在客户端:
# Set multicast interface
ifi = socket.if_nametoindex(ifn)
ifis = struct.pack("I", ifi)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)