我有一个Python程序,它使用套接字在多播IP地址224.0.1.1和UDP端口20001上发送和接收UDP多播消息 .
在接收端,我创建一个单独的接收套接字,并使用套接字选项IP_ADD_MEMBERSHIP调用socket.setsockopt一次以加入IP多播组 .
但是,Wireshark报告对setsockopt的单次调用导致发送两个单独的连接(IGMPv2成员报告)消息:
使用以太网源地址01:00:52:00:01:01的一个加入消息,这是与IP多播组对应的以太网多播地址 .
使用以太网源地址a8:66:7f:3a:2b:1a的一个加入消息,它是与发送加入消息的物理“en0”接口相对应的以太网单播地址 .
在发送方面,我创建一个发送套接字,一个调用socket.connect来将套接字与多播IP地址224.0.1.1和UDP端口20001相关联 .
然后我调用socket.send一次发送一条测试消息 . 由于两个单独的连接消息,所发送的测试消息在线路上显示为TWICE,一次使用目标以太网地址01:00:52:00:01:01,一次使用目标以太网地址a8:66:7f:3a:2b: 1A .
在接收方,两个消息都是单独接收的 . 因此,每个发送的消息都是TWICE接收的 .
问题是:我怎样才能防止这种情况发生?
再现行为的最小示例如下:
import socket
import struct
import time
mcast_ipv4_address = "224.0.1.1"
port = 20001
group = (mcast_ipv4_address, port)
txsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
txsock.connect(group)
rxsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
req = struct.pack("=4sl", socket.inet_aton(mcast_ipv4_address), socket.INADDR_ANY)
rxsock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, req)
rxsock.bind(group)
time.sleep(1.0)
print("Sending single message...")
msg = b"test"
txsock.send(msg)
print("Sent {}".format(msg))
print("Receiving first message...")
msg = rxsock.recv(65535)
print("Received {}".format(msg))
print("Receiving second message...")
msg = rxsock.recv(65535)
print("Received {}".format(msg))
time.sleep(0.1)
额外细节:
1)操作系统是macOS High Sierra 10.13.5
2)Python版本是3.5.1
3)第一次睡眠是必不可少的;没有它,问题不会发生,因为它需要一些时间来发送加入消息
4)第二次睡眠不是必需的;在程序终止和发送离开消息之前,确保wireshark都能看到两条测试消息 .
5)我尝试使用输出接口的真实IP地址而不是req结构中的INADDR_ANY,但它没有任何区别 .