Welcome to the next pikoTutorial!
The minimal receiver
import struct from argparse import ArgumentParser from socket import socket, AF_INET, SOCK_DGRAM, inet_aton, IPPROTO_IP, \ IP_ADD_MEMBERSHIP, INADDR_ANY, SOL_SOCKET, SO_REUSEADDR # define command line interface parser = ArgumentParser(description='UDP Multicast Receiver') parser.add_argument('-mc_address', help='Multicast address') # parse command line options args = parser.parse_args() # create a UDP socket with socket(AF_INET, SOCK_DGRAM) as receiver_socket: # on the socket level, set the ability to reuse address receiver_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # bind the socket to the receiver's own address and port multicast_ip = args.mc_address.split(':')[0] multicast_port = args.mc_address.split(':')[1] receiver_socket.bind((multicast_ip, int(multicast_port))) # set up the multicast group membership by converting addresses to # 4sl (4 byte string and 4 byte long integer) multicast_request = struct.pack("4sl", inet_aton(multicast_ip), INADDR_ANY) # join the multicast group receiver_socket.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, multicast_request) print(f'Receiver listening on {multicast_ip}:{multicast_port}') # receive messages (in this case, indefinitely until interrupted) data, sender_address = receiver_socket.recvfrom(1024) # Buffer size 1024 bytes print(f'Received message from {sender_address[0]}:{sender_address[1]} : {data.decode()}')
Note for beginners: do not remove line 14 from the receiver implementation! Without the ability to re-use the same address, you will not be able to run more than 1 multicast receiver and you’ll end up with a simple UDP client/server setup.
The minimal sender
import time from argparse import ArgumentParser from socket import socket, AF_INET, SOCK_DGRAM, IPPROTO_UDP # define command line interface parser = ArgumentParser() parser.add_argument('-sender_address', help='Sender\'s source address') parser.add_argument('-mc_address', nargs='+', help='List of multicast addresses separated by space') # parse command line options args = parser.parse_args() # create a UDP socket with socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) as sender_socket: # assign sender specific source port sender_ip: str = args.sender_address.split(':')[0] sender_port: int = int(args.sender_address.split(':')[1]) sender_socket.bind((sender_ip, sender_port)) # send the message to each multicast address in the list for address in args.mc_address: multicast_ip: str = address.split(':')[0] multicast_port: int = int(address.split(':')[1]) sender_socket.sendto(f'This message is for {multicast_ip}:{multicast_port} receivers'.encode(), (multicast_ip, multicast_port))
Multicast on a single IP and a single port
The simplest scenario assumes 1 sender sending from 127.0.0.1:3000 address to 2 receivers listening on the shared 224.0.0.1:5000 multicast address:

To achieve that, run as many receivers as you want with command:
python3 receiver.py -mc_address 224.0.0.1:5000
And the sender with command:
python3 sender.py -sender_address 127.0.0.1:3000 -mc_address 224.0.0.1:5000
Note for beginners: multicast IPs can range from 224.0.0.0 to 239.255.255.255.
Multicast on a single IP and multiple ports
In this setup 1 sender sends message from 127.0.0.1:3000 address to a single multicast IP and two multicast ports: 224.0.0.1:5000 and 224.0.0.1:5001.

Run first group of receivers with command:
python3 receiver.py -mc_address 224.0.0.1:5000
And the second group of receivers with command:
python3 receiver.py -mc_address 224.0.0.1:5001
After that you can send a multicast messages to all of them running sender with the following command:
python3 sender.py -sender_address 127.0.0.1:3000 -mc_address 224.0.0.1:5000 224.0.0.1:5001
Multicast on multiple IPs
Groups of receivers can be of course differentiated also by multicast IP.

Note for beginners: in this example I decided to not specify the sender’s IP. In the previous examples, I used loopback interface on which 127.0.0.1 IP is always available, but multiple multicast IPs on that interface may not work on your machine without additional configuration. I don’t know what are real network interfaces available on your machine and what IPs are assigned on them, so I let the operating system choose it automatically by leaving the sender’s IP empty.
For that, run the first group of receivers with command:
python3 receiver.py -mc_address 224.0.0.1:5000
And the second group of receivers with command:
python3 receiver.py -mc_address 224.0.0.2:5000
Now the only thing left to do is to launch the multicast sender (leaving the IP empty – see the note above):
python3 sender.py -sender_address :3000 -mc_address 224.0.0.1:5000 224.0.0.2:5000