我正在尝试为Python中的IPv6多播通信设计一个简单的客户端/服务器对。到目前为止我的代码似乎符合我在网上看到的例子,但我的服务器从未接收过数据。
我在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)
任何意见都会受到赞赏。
答案 0 :(得分:1)
除了所有其他好建议之外:将服务器上的套接字绑定到链接本地地址。这将过滤传入的数据包,以便只有具有该目标地址的数据包到达您的代码。发往多播地址的数据包将被丢弃。尝试绑定到::并确保在继续使用更复杂的东西之前可以正常工作。
答案 1 :(得分:0)
您不能将"ff10::
用作IPv6多播地址。您在该地址中使用的范围0
是保留的。 IPv6多播需要考虑多个RFC,它们使用标志和范围。例如,范围1
是接口本地范围,发送到具有该范围的组的流量不会将本地接口留在发送主机上。
有关最新的范围,请参阅RFC 7346, IPv6 Multicast Address Scopes:
- 醇>
IPv6多播地址范围的定义(更新RFC 4291)
下表更新了[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表示永久分配(“众所周知的”)多播 地址,由互联网号码分配机构(IANA)指定。
T = 1表示非永久性分配(“瞬态”或 “动态”分配的)多播地址。
编辑2:
顺便说一下,你不能在IPv6组播中使用零地址:
预留的多播地址:
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。
答案 2 :(得分:0)
我也必须在客户端设置多播接口。客户端和服务器都有一个虚拟接口和一个可操作的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)