I have a Python program that uses a sockets to send and receive UDP multicast messages on multicast IP address 224.0.1.1 and UDP port 20001.
On the receive the side, I create a single receive socket, and call socket.setsockopt once using socket option IP_ADD_MEMBERSHIP to join the IP multicast group.
However, Wireshark reports that the single call to setsockopt causes two separate join (IGMPv2 membership report) messages to be sent out:
One join message using Ethernet source address 01:00:52:00:01:01, which is the Ethernet multicast address corresponding to the IP multicast group.
One join message using Ethernet source address a8:66:7f:3a:2b:1a, which is the Ethernet unicast address corresponding to the physical "en0" interface over which the join message was sent.
On the send side, I create a single send socket, an call socket.connect to associate the socket with multicast IP address 224.0.1.1 and UDP port 20001.
I then call socket.send once to send a single test message. Because of the two separate join messages, the sent test message appears TWICE on the wire, once with destination Ethernet address 01:00:52:00:01:01 and once with destination Ethernet address a8:66:7f:3a:2b:1a.
On the receiving side, both messages are received separately. Thus each sent message is received TWICE.
The question is: how can I prevent this from happening?
A minimal example that reproduces the behavior is as follows:
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)
Additional details:
1) The operating system is macOS High Sierra 10.13.5
2) The Python version is 3.5.1
3) The first sleep is essential; without it the problem does not occur because it takes some time for the join messages to be sent
4) The second sleep is not essential; it is there to make sure both test messages are seen by wireshark before the program terminates and the leave messages are sent.
5) I tried using the real IP address of the outgoing interface in stead of INADDR_ANY in the req structure, but it does not make any difference.