How do you send and receive UDP multicast in Python? Is there a standard library to do so?
10 Answers
This works for me:
Receive
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
IS_ALL_GROUPS = True
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
# on this port, receives ALL multicast groups
sock.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
sock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
# For Python 3, change next line to "print(sock.recv(10240))"
print sock.recv(10240)
Send
import socket
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
# regarding socket.IP_MULTICAST_TTL
# ---------------------------------
# for all packets sent, after two hops on the network the packet will not
# be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html)
MULTICAST_TTL = 2
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
# For Python 3, change next line to 'sock.sendto(b"robot", ...' to avoid the
# "bytes-like object is required" msg (https://stackoverflow.com/a/42612820)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
It is based off the examples from http://wiki.python.org/moin/UdpCommunication which didn't work.
My system is... Linux 2.6.31-15-generic #50-Ubuntu SMP Tue Nov 10 14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4

- 655
- 1
- 7
- 22

- 11,015
- 10
- 48
- 62
-
7For mac os x you need to use the socket.SO_REUSEPORT option as an alternative to socket.SO_REUSEADDR in the above example, to permit multiple listeners on the same multicast port address combination. – atikat Sep 08 '11 at 05:01
-
1For sending, i also needed "sock.bind((
, 0))" because my multicast listener was bound to a specific adapter. – Mark Foreman Nov 09 '12 at 02:04 -
2for udp multicast you need to bind to multicast group/port not the local group port, `sock.bind((MCAST_GRP, MCAST_PORT))`, your code might and might not work, it may not work when you have multiple nics – stefanB Jan 21 '13 at 22:22
-
@atikat : Thanks!! Although why do we need this on the MAC but not on Ubuntu ? – Kyuubi Nov 04 '13 at 15:52
-
@stefanB makes a great point. As it stands, the code `sock.bind(('', MCAST_PORT))` will receive messages on *ALL* groups on that port, not just the group being joined. Replace `''` with `MCAST_GRP` to receive only from that group. I'll add a comment to the code to make this more prominent. – Randall Cook Apr 23 '15 at 21:25
-
Do you maybe know an answer to the question over [here](https://stackoverflow.com/questions/35876323/netlink-multicast-in-kernels-above-4)? – user1252280 Mar 10 '16 at 18:38
-
4@RandallCook: When I replace '' by MCAST_GRP I get socket.error: [Errno 10049] The requested address is not valid in its context – stewbasic Mar 22 '16 at 08:06
-
If you want to use a specific address for the mreq interface instead of `socket.INADDR_ANY`, the format string for `struct.pack` is `4s4s`. – Martin Pecka Apr 13 '18 at 08:59
-
python 3 needs `struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)` (struct.pack has evolved and is less permissive) – Jean-François Fabre May 04 '18 at 14:44
-
Not works when from two pcs within a same local area network. Not yet figure out why. – W.Perrin Nov 08 '19 at 11:40
-
I have created a gist and added two command-line arguments: https://gist.github.com/knotman90/3a970484b97bb6e42ad7db606b881178 – Davide Spataro Jan 26 '22 at 10:27
Multicast sender that broadcasts to a multicast group:
#!/usr/bin/env python
import socket
import struct
def main():
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock.sendto('Hello World!', (MCAST_GRP, MCAST_PORT))
if __name__ == '__main__':
main()
Multicast receiver that reads from a multicast group and prints hex data to the console:
#!/usr/bin/env python
import socket
import binascii
def main():
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except AttributeError:
pass
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
sock.bind((MCAST_GRP, MCAST_PORT))
host = socket.gethostbyname(socket.gethostname())
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(host))
sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MCAST_GRP) + socket.inet_aton(host))
while 1:
try:
data, addr = sock.recvfrom(1024)
except socket.error, e:
print 'Exception'
else:
hexdata = binascii.hexlify(data)
print 'Data = %s' % hexdata
if __name__ == '__main__':
main()

- 325
- 1
- 8

- 41
- 1
- 4
-
1I tried this, it did not work. In Wireshark I can see the transmit, but I don't see any IGMP join stuff and I don't receive anything. – Gordon Wrigley Nov 25 '09 at 02:46
-
2you need to bind to multicast group/port not local port on multicast address, `sock.bind((MCAST_GRP, MCAST_PORT))` – stefanB Jan 21 '13 at 22:24
-
1This example doesn't work for me, for an obscure reason. Using socket.gethostbyname(socket.gethostname()) to select the interface doesn't always elect the external interface - in fact, on debian systems, it tends to select the loopback address. Debian adds an entry of 127.0.1.1 in the host table for the hostname. Instead, it is more effective to use socket.INADDR_ANY , which the higher ranking answer uses through the 'pack' statement ( which is more correct than the '+' ). Also, the use of IP_MULTICAST_IF is not required, as the higher ranking answer correctly states. – Brian Bulkowski Jul 13 '16 at 05:50
-
1@BrianBulkowski there are many programmers who use socket.INADDR_ANY, to the great woe and consternation of those of us with multiple interfaces, that need the multicast data to come on a particular interface. The solution is not socket.INADDR_ANY. It is to select the proper interface by IP address, however you think is best (a config file, asking the end user, however you choose for your application's needs). socket.INADDR_ANY will get you the multicast data, true, and is easiest if you a assume a single-homed host, but I think it's less correct. – Mike S Sep 02 '16 at 18:13
-
@MikeS while I agree with you in some principle, the idea of using IP addresses to select interfaces is terribly, terribly fraught. I know the problem well, but in a dynamic world, and IP address isn't the answer. So you need to write code that iterates everything and chooses by interface name, looks at the interface name, picks out the current IP address, and uses that. Hopefully, the IP address hasn't changed in the meantime. I wish that Linux/Unix had standardized on using interface names everywhere, and the programming languages had, that would make a config file more sensible. – Brian Bulkowski Nov 19 '16 at 00:49
-
@BrianBulkowski if the IP address has changed in the meantime you are probably not in a corporate environment with static IPs on multiple interfaces and hundreds of servers. Maybe you're on a laptop with a wireless and LAN interface, I don't know. But the fact is, INADDR_ANY can be a big problem, and we have to fix software that specifies it because you really don't want your multicast data to come in on a 1Gig interface if you need it on a 10Gig interface. Programmers who paint with a wide brush, assuming that the system is unknowable or uncontrolled, are the bane of my existence. – Mike S Nov 21 '16 at 15:56
-
...anyway, future generations who study this problem should understand all facets of the situation, which ultimately is my point. INADDR_ANY *may* get you what you want. Then again, it may not. Know your systems and your use case, and please be kind to your systems administrator who may spend a number of long and painful hours debugging these situations. – Mike S Nov 21 '16 at 16:00
-
Do we need to edit the receiver so that the last two lines of the 'except' block are moved to the 'try' block? Seems like as-is the receiver has no output at all. – ChrisCantrell Jul 24 '19 at 14:39
In order to Join multicast group Python uses native OS socket interface. Due to portability and stability of Python environment many of socket options are directly forwarded to native socket setsockopt call. Multicast mode of operation such as joining and dropping group membership can be accomplished by setsockopt
only.
Basic program for receiving multicast IP packet can look like:
from socket import *
multicast_port = 55555
multicast_group = "224.1.1.1"
interface_ip = "10.11.1.43"
s = socket(AF_INET, SOCK_DGRAM )
s.bind(("", multicast_port ))
mreq = inet_aton(multicast_group) + inet_aton(interface_ip)
s.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, str(mreq))
while 1:
print s.recv(1500)
Firstly it creates socket, binds it and triggers triggers multicast group joining by issuing setsockopt
. At very end it receives packets forever.
Sending multicast IP frames is straight forward. If you have single NIC in your system sending such packets does not differ from usual UDP frames sending. All you need to take care of is just set correct destination IP address in sendto()
method.
I noticed that lot of examples around Internet works by accident in fact. Even on official python documentation. Issue for all of them are using struct.pack incorrectly. Please be advised that typical example uses 4sl
as format and it is not aligned with actual OS socket interface structure.
I will try to describe what happens underneath the hood when exercising setsockopt call for python socket object.
Python forwards setsockopt method call to native C socket interface. Linux socket documentation (see man 7 ip
) introduces two forms of ip_mreqn
structure for IP_ADD_MEMBERSHIP option. Shortest is form is 8 bytes long and longer is 12 bytes long. Above example generates 8 byte setsockopt
call where first four bytes define multicast_group
and second four bytes define interface_ip
.

- 3
- 4

- 1
- 1
- 1
Just another answer to explain some subtle points in the code of the other answers:
socket.INADDR_ANY
- (Edited) In the context ofIP_ADD_MEMBERSHIP
, this doesn't really bind the socket to all interfaces but just choose the default interface where multicast is up (according to routing table)- Joining a multicast group isn't the same as binding a socket to a local interface address
see What does it mean to bind a multicast (UDP) socket? for more on how multicast works
Multicast receiver:
import socket
import struct
import argparse
def run(groups, port, iface=None, bind_group=None):
# generally speaking you want to bind to one of the groups you joined in
# this script,
# but it is also possible to bind to group which is added by some other
# programs (like another python program instance of this)
# assert bind_group in groups + [None], \
# 'bind group not in groups to join'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# allow reuse of socket (to allow another instance of python running this
# script binding to the same ip/port)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('' if bind_group is None else bind_group, port))
for group in groups:
mreq = struct.pack(
'4sl' if iface is None else '4s4s',
socket.inet_aton(group),
socket.INADDR_ANY if iface is None else socket.inet_aton(iface))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print(sock.recv(10240))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--port', type=int, default=19900)
parser.add_argument('--join-mcast-groups', default=[], nargs='*',
help='multicast groups (ip addrs) to listen to join')
parser.add_argument(
'--iface', default=None,
help='local interface to use for listening to multicast data; '
'if unspecified, any interface would be chosen')
parser.add_argument(
'--bind-group', default=None,
help='multicast groups (ip addrs) to bind to for the udp socket; '
'should be one of the multicast groups joined globally '
'(not necessarily joined in this python program) '
'in the interface specified by --iface. '
'If unspecified, bind to 0.0.0.0 '
'(all addresses (all multicast addresses) of that interface)')
args = parser.parse_args()
run(args.join_mcast_groups, args.port, args.iface, args.bind_group)
sample usage: (run the below in two consoles and choose your own --iface (must be same as the interface that receives the multicast data))
python3 multicast_recv.py --iface='192.168.56.102' --join-mcast-groups '224.1.1.1' '224.1.1.2' '224.1.1.3' --bind-group '224.1.1.2'
python3 multicast_recv.py --iface='192.168.56.102' --join-mcast-groups '224.1.1.4'
Multicast sender:
import socket
import argparse
def run(group, port):
MULTICAST_TTL = 20
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
sock.sendto(b'from multicast_send.py: ' +
f'group: {group}, port: {port}'.encode(), (group, port))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--mcast-group', default='224.1.1.1')
parser.add_argument('--port', default=19900)
args = parser.parse_args()
run(args.mcast_group, args.port)
sample usage: # assume the receiver binds to the below multicast group address and that some program requests to join that group. And to simplify the case, assume the receiver and the sender are under the same subnet
python3 multicast_send.py --mcast-group '224.1.1.2'
python3 multicast_send.py --mcast-group '224.1.1.4'

- 429
- 8
- 16
Have a look at py-multicast. Network module can check if an interface supports multicast (on Linux at least).
import multicast
from multicast import network
receiver = multicast.MulticastUDPReceiver ("eth0", "238.0.0.1", 1234 )
data = receiver.read()
receiver.close()
config = network.ifconfig()
print config['eth0'].addresses
# ['10.0.0.1']
print config['eth0'].multicast
#True - eth0 supports multicast
print config['eth0'].up
#True - eth0 is up
Perhaps problems with not seeing IGMP, were caused by an interface not supporting multicast?

- 7,884
- 2
- 32
- 24
To make the client code (from tolomea) work on Solaris you need to pass the ttl value for the IP_MULTICAST_TTL
socket option as an unsigned char. Otherwise you will get an error.
This worked for me on Solaris 10 and 11:
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
ttl = struct.pack('B', 2)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))

- 1
- 1
GumD and GumC https://github.com/futzu/gumd
I use GumD mostly for video, but you can use any kind of file.
pip3 install gumd
gumd (Daemon)
>>>> from gumd import GumD
>>>> gumd =GumD('235.35.3.5:3535',1)
>>>> gumd.mcast("/home/a/stuff.txt")
# Can also use http(s), UDP and multicast
stream uri: udp://@235.35.3.5:3535
>>>>
Use gumc (Client)
>>>> from gumc import GumC
>>>> gumc = GumC("udp://@235.35.3.5:3535")
>>>> data = gumc.read(8)
>>>> data
b'Helloooo'

- 329
- 1
- 4
For the Windows programmers out there, the following code snippet works on both Windows and Linux.
Examples that use SOL_IP will cause errors on Windows for Python versions >3.x.12.
Many examples don't include setting IP_MULTICAST_IF. This can be important for systems with multiple interfaces. On Windows IP_MULTICAST_IF is required to specify the network interface because Windows cannot bind to the multicast address.
import socket
import platform
from contextlib import closing
address = "239.50.50.50"
port = 6000
network_adapter = "172.16.0.93"
with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)) as sock:
# SO_REUSEADDR: allows binding to port potentially already in use
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# linux binds to multicast address, windows to interface address
ip_bind = network_adapter if platform.system() == "Windows" else address
sock.bind((ip_bind, port))
# socket.IPPROTO_IP works on Linux and Windows
# IP_MULTICAST_IF: force sending network traffic over specific network adapter
# IP_ADD_MEMBERSHIP: join multicast group
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(network_adapter))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(address) + socket.inet_aton(network_adapter))
# send recv examples
# sock.sendto(b"Hello World", (address, port))
# data, server = sock.recvfrom(2**8)

- 71
- 4
-
1I was discussing this very thing today, I'm glad I saw your post, I was pushing for socket.IPPROTO_IP, socket.IP_MULTICAST_IF, and I didnt have a good argument against using SOL_SOCKET, but you just gave me one, thanks man. – Leroy Scandal Mar 09 '23 at 00:47
tolomea's answer worked for me. I hacked it into socketserver.UDPServer too:
class ThreadedMulticastServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
def __init__(self, *args):
super().__init__(*args)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

- 630
- 7
- 24