Python 3 IPv6 多播

Python 3 IPv6 Multicast

我正在尝试为 Python 中的 IPv6 多播通信设计一个简单的 client/server 对。到目前为止,我的代码似乎符合我在网上看到的示例,但我的服务器从未接收到数据。

我在 ip maddr shownetstat -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

  1. 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)