Python 3 IPv6多播

时间:2018-06-14 02:13:13

标签: python python-3.x ipv6 multicast

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

我在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)

任何意见都会受到赞赏。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

您不能将"ff10::用作IPv6多播地址。您在该地址中使用的范围0是保留的。 IPv6多播需要考虑多个RFC,它们使用标志和范围。例如,范围1是接口本地范围,发送到具有该范围的组的流量不会将本地接口留在发送主机上。

有关最新的范围,请参阅RFC 7346, IPv6 Multicast Address Scopes

  
      
  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     |
    +------+--------------------------+-------------------------+
    
  2.   

修改

根据您对原始问题的更改,您无法正确计算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)