Python3 IPv6多播

Python3 IPv6多播,python,python-3.x,ipv6,multicast,Python,Python 3.x,Ipv6,Multicast,我试图用Python为IPv6多播通信设计一个简单的客户机/服务器对。到目前为止,我的代码似乎符合我在网上看到的示例,但我的服务器从未接收数据 我在ipmaddr show和netstat-g中看到订阅。tcpdump显示:10:13:36.913546 IP6(流标签0x77fe8,hlim 5,下一个报头UDP(17)有效负载长度:20)**省略**>ff16::fe.commplex-main:[UDP总和确定]UDP,长度12 客户端和服务器连接到同一交换机,IPv6单播地址位于同一子网

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

我在
ipmaddr show
netstat-g
中看到订阅。tcpdump显示:
10:13:36.913546 IP6(流标签0x77fe8,hlim 5,下一个报头UDP(17)有效负载长度:20)**省略**>ff16::fe.commplex-main:[UDP总和确定]UDP,长度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,使用标志和范围。例如,scope
1
是接口本地作用域,发送到具有该作用域的组的流量不会离开发送主机上的本地接口

有关最新的作用域,请参见:

  • 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     |
    +------+--------------------------+-------------------------+
    

  • 编辑:

    # Set multicast interface
    ifi = socket.if_nametoindex(ifn)
    ifis = struct.pack("I", ifi)
    sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
    
    根据对原始问题的更改,您没有正确计算UDP校验和,这对于IPv4是可选的,但对于IPv6是必需的

    此外,由于您正在创建自己的多播地址(不是IANA分配的地址),因此还应返回使用
    T
    标志作为
    1

    T=0表示永久分配的(“已知”)多播 地址,由互联网分配号码管理局(IANA)分配

    T=1表示非永久性分配(“瞬态”或 “动态”分配的)多播地址


    编辑2:

    # Set multicast interface
    ifi = socket.if_nametoindex(ifn)
    ifis = struct.pack("I", ifi)
    sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
    
    顺便说一下,您不能在IPv6多播中使用零地址:

    保留多播地址:
    FF00:0:0:0:0:0:0

    FF01: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

    FF05:0:0:0:0:0:0:0

    FF06:0:0:0:0:0:0

    FF07:0:0:0:0:0:0

    FF08:0:0:0:0:0:0

    FF09:0:0:0:0:0:0:0

    FF0A:0:0:0:0:0:0

    FF0B:0:0:0:0:0:0

    FF0C:0:0:0:0:0:0

    FF0D:0:0:0:0:0:0

    FF0E:0:0:0:0:0:0

    FF0F:0:0:0:0:0:0:0


    听起来,在尝试使用IPv6多播之前,您真的、真的需要研究RFC。

    除了所有其他好的建议之外:将服务器上的套接字绑定到链接本地地址。这将过滤传入的数据包,以便只有具有该目标地址的数据包才能到达您的代码。发送到多播地址的数据包将被丢弃。尝试绑定到::并确保在继续进行更复杂的操作之前能够正常工作。

    我还必须在客户端设置多播接口。客户机和服务器都有一个虚拟接口和一个可操作的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)
    

    这似乎允许程序开始发送数据包,但是服务器仍然没有接收到它。带有-vv的tcpdump显示:
    >ff06::.5000:[错误的udp校验和0xb590->0xf470!]UDP,长度12
    ,我已经更新了问题,感谢您的关注。再次感谢,我已经修改了我的代码以使用正确的多播地址。问题是UDP校验和哪里出错了?我不确定,我看不出它在哪里计算。校验和似乎不再是问题。客户端和服务器在同一网络上吗?无法通过Internet路由多播数据包。客户端和服务器在同一网络上。“客户端和服务器在同一网络上。”然后,您应该使用链接本地作用域:
    ff12::fe
    。您似乎仍然错误地计算UDP校验和。"IPv4和IPv6使用UDP的关键区别在于,由于缺少IPv6报头校验和,RFC 2460强制使用计算出的UDP校验和,即非零值。校验和计算中包含的伪报头提供了一种统计检查,确保数据报已传递到预定的IPv6目标节点。[RFC1071]中描述了校验和计算的算法。"在这种情况下,未分配的作用域是否应该与链接本地作用域一样有效?就UDP校验和而言,我还需要在代码中做些什么?根据RFC,您应该能够使用未分配的作用域,但我不会,因为它可能会在某个点被重新定义,例如,直到这个RFC,领域本地被取消分配,现在您在尝试使用该作用域时可能会遇到麻烦。Admin Local对于您自己的使用非常常见。将其更改为:,仍然没有骰子。服务器计算机上的跟踪没有看到任何内容,发送计算机:
    10:13:36.913546 IP6(flowlabel 0x77fe8,hlim 5,下一个标头UDP(17)有效负载长度:20)**省略**>ff16::fe.commplex-main:[udp sum ok]udp,长度12
    由于某些原因,校验和现在似乎正常了……我将在帖子中添加有关网络设置的更多详细信息。这可能也是代码的问题。感谢您的关注。