Skip to content

Instantly share code, notes, and snippets.

@ninedraft
Last active January 29, 2024 23:27
Show Gist options
  • Star 58 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save ninedraft/7c47282f8b53ac015c1e326fffb664b5 to your computer and use it in GitHub Desktop.
Save ninedraft/7c47282f8b53ac015c1e326fffb664b5 to your computer and use it in GitHub Desktop.
Python udp broadcast client server example.

Python udp broadcast client-server example

⚠️ ❗ ATTENTION ❗ ⚠️

This gist is deprecated and will not be edited in the future. Consider visit ninedraft/python-udp repo. It will not be deleted, however.

⚠️ ❗ ATTENTION ❗ ⚠️

Works for python 3.7 and 2.7 for Mac OS and Linux(kernel>=3.9) hosts. If you'ra using linux(kernel<3.9), then use socket.O_REUSEADDR instead of socket.SO_REUSEPORT to share (host, port) between multiple clients and servers.

Tricks and traps:

import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP
# Enable port reusage so we will be able to run multiple clients and servers on single (host, port).
# Do not use socket.SO_REUSEADDR except you using linux(kernel<3.9): goto https://stackoverflow.com/questions/14388706/how-do-so-reuseaddr-and-so-reuseport-differ for more information.
# For linux hosts all sockets that want to share the same address and port combination must belong to processes that share the same effective user ID!
# So, on linux(kernel>=3.9) you have to run multiple servers and clients under one user to share the same (host, port).
# Thanks to @stevenreddie
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
# Enable broadcasting mode
client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
client.bind(("", 37020))
while True:
# Thanks @seym45 for a fix
data, addr = client.recvfrom(1024)
print("received message: %s"%data)
import socket
import time
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Enable port reusage so we will be able to run multiple clients and servers on single (host, port).
# Do not use socket.SO_REUSEADDR except you using linux(kernel<3.9): goto https://stackoverflow.com/questions/14388706/how-do-so-reuseaddr-and-so-reuseport-differ for more information.
# For linux hosts all sockets that want to share the same address and port combination must belong to processes that share the same effective user ID!
# So, on linux(kernel>=3.9) you have to run multiple servers and clients under one user to share the same (host, port).
# Thanks to @stevenreddie
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
# Enable broadcasting mode
server.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# Set a timeout so the socket does not block
# indefinitely when trying to receive data.
server.settimeout(0.2)
message = b"your very important message"
while True:
server.sendto(message, ('<broadcast>', 37020))
print("message sent!")
time.sleep(1)
@ma-lemire
Copy link

data, addr = client.recvfrom(1024) ?

@seym45
Copy link

seym45 commented Aug 28, 2018

data, addr = sock.recvfrom(1024) should be
as data, addr = client.recvfrom(1024)

@worldofchris
Copy link

Very useful gist. Needs fixing as per the two comments above though :-)

@gistrec
Copy link

gistrec commented Oct 18, 2018

thx

@p2pNinja
Copy link

I notice that the port number of the client (37020) is already known by the server (which sends the request to ('', 37020)). is this necessary. is there a way around this?

@ninedraft
Copy link
Author

Very useful gist. Needs fixing as per the two comments above though :-)

Thx. I fixed client.py

@ninedraft
Copy link
Author

https://gist.github.com/ninedraft/7c47282f8b53ac015c1e326fffb664b5#gistcomment-3063057

I notice that the port number of the client (37020) is already known by the server (which sends the request to ('', 37020)). is this necessary. is there a way around this?

Nope, you have to know the exact port your clients are listen on. Different UDP apps and protocols uses predefined ports.
Examples: https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

@stevenreddie
Copy link

I just came across this gist while searching for a quick snippet to copy/paste (thanks). I won't say that the following is required, though it would be unusual not to include it.

In both the client and server, the following line should be included right before each SO_BROADCAST line (that precise order is not critical, but a good place to do it):

client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    # change `client` to `server` for server.py

This makes it possible to run multiple clients and servers on a single host, on the same port. With broadcast messages that aren't just simple strings as in this example, all of those clients/servers will play nicely with each other even on the one port as long as the protocols (messages) can be distinguished from each other by content.

For example, without this change, attempting to run two copies of either the client or the server with the code at top will result in something like this:

$ ./server.py & ./server.py &
[1] 32734
[2] 32735
$ Traceback (most recent call last):
  File "./server.py", line 12, in <module>
    server.bind(("", 44444))
  File "/usr/lib/python2.7/socket.py", line 228, in meth
message sent!
    return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use
message sent!
message sent!
message sent! (the second process failed and exited, and the first continues)

Whereas with the change there will be two "message sent!" lines printed each second (one for each server).

@ninedraft
Copy link
Author

ninedraft commented Nov 26, 2019

@stevenreddie thanks for your contribution!
I did a tiny bit of R&D and found this thread about socket tripwires, so I applied SO_REUSEPORT flag. SO_REUSEADDR doesn't allow to use a shared port on *BSD systems (Mac OS including). Also, on linux(kernel>=3.9) you have to run multiple servers and clients under one user to share the same (host, port) because for linux hosts all sockets that want to share the same address and port combination must belong to processes that share the same effective user ID.

@stevenreddie
Copy link

stevenreddie commented Nov 26, 2019

I'm actually doing this on macOS. I can post the full code snippets here if it helps. Though, looks like the main differences with the updated code up top are:

  1. I'm using SO_REUSEADDR.
  2. I include socket.IPPROTO_UDP as the 3rd parameter to socket.socket() in client.py.
  3. I don't do the bind in server.py.

@ninedraft
Copy link
Author

ninedraft commented Nov 26, 2019

I currently use Mac OS Catalina 10.15.1 and Python 2.7.16 and Python 3.7.5 and I can't use SO_REUSEADDR to share ports. What version of Mac OS do you have?

I can post the full code snippets here if it helps

It will be very useful, thanks!

@stevenreddie
Copy link

Sorry, you're correct on that one. I was ssh'd into a Raspberry Pi and working on both platforms. I used SO_REUSEADDR on the RPi.

@ninedraft
Copy link
Author

ninedraft commented Nov 26, 2019

Sorry, you're correct on that one.

But your solution actually works on linux and mac os both. I forgot to mark client socket as UDP, and if you don't to listen incoming messages on server, than you can omit port binding. I've checked it for Mac OS and linux. So I've applied your fix 👌

I'm thinking about a separate repo with this example since related thread and code keep growing.

@alexdrm98
Copy link

alexdrm98 commented Feb 1, 2020

Traceback (most recent call last): File "brd_serv.py", line 150, in <module> clt_brd() File "brd_serv.py", line 23, in clt_brd client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP AttributeError: type object 'socket' has no attribute 'socket'

I'm getting this error. I actually put client.py and server.py in a same file and called client(). Then this is the output. What might be the issue?

`def ser_brd_name():
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
server.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
server.settimeout(0.2)
nam='BEN'
num=9999
#message = b'%s: %s' % (nam.encode('utf-8'), ip.encode('utf-8')
message = str.encode(nam)
while True:
server.sendto(message,('192.168.43.255',12345))
print("Broadcast")
time.sleep(1)

def clt_brd():
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)`

# Enable broadcasting mode
client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

client.bind(('', 12345))
while True:
	data,addr = client.recvfrom(1024)

	#print("received message: %s"%data)
	acaddr=addr[0]
	acdata=data.decode()
	alldata={acdata:acaddr}
	for x,y in alldata.items():
		print(x,y)

`

@ninedraft
Copy link
Author

Traceback (most recent call last): File "brd_serv.py", line 150, in <module> clt_brd() File "brd_serv.py", line 23, in clt_brd client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP AttributeError: type object 'socket' has no attribute 'socket'

I'm getting this error. I actually put client.py and server.py in a same file and called client(). Then this is the output. What might be the issue?

Perhaps you redeclared the variable socket somewhere in the code?

@guytas
Copy link

guytas commented Jun 23, 2020

Is there another way to receive packets without hanging on the line recvfrom ?
I would like to test if the a udp line has been received before going to go get it. This way, I can do other things in the mean time.

@Hugueskir
Copy link

Why can't I connect more then 1 client?

@bpsib
Copy link

bpsib commented Nov 22, 2020

I have tried the server on Raspberry Pi but I just get message sent! every second and doesn't work. I have also tried changing socket.SO_REUSEPORT to socket.SO_REUSEADDR but made no difference. Why isn't it working for me?

EDIT: Tried again and now it's working.

@tianxie1989
Copy link

  1. in mac pc, send and receive message all success, server and client program all work well;
  2. in ubuntu 16.04 , i found just the server "message sent !" works but client got nothing ???

@ninedraft
Copy link
Author

@bpsib @tianxie1989 I've fixed the broadcast host.
Try this for now please
https://github.com/ninedraft/python-udp

@shehryar51088
Copy link

with your code how can I print IP Address Of Clients connected to SERVER,please help

@ninedraft
Copy link
Author

with your code how can I print IP Address Of Clients connected to SERVER,please help

There is no such thing as connection in UDP, and server doesn't see any clients. It basically throws packets in the network and receives no answers.

https://www.youtube.com/watch?v=FfvUxw8DHb0

@UgraNarasimha
Copy link

I tried with windows powershell, the client.py just blinks into oblivion and no message is received. Also I have a problem with breaking the function with CTRL+C since everything just freezes. Any tips to solve this?

@ninedraft
Copy link
Author

@UgraNarasimha I'll try to reproduce it
Please, add an issue here https://github.com/ninedraft/python-udp

@haskiindahouse
Copy link

haskiindahouse commented Jun 3, 2021

How I do it not in local network?
I'm trying do this:
client.bind(("broadcast_station_ip", 37020))
And I'm getting this:
Traceback (most recent call last): File "client.py", line 15, in <module> client.bind(("broadcast_station_ip", 37020)) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth return getattr(self._sock,name)(*args) socket.error: [Errno 49] Can't assign requested address
For client.py I'm using macOS Big Sur 11.2.3 and for server.py I'm using Ubuntu 20.10.
It's work fine when:
client.bind(("", 37020))
and computers placed in local network.
If you have some idea or tips for solve this, please help me :)

@weihohoho
Copy link

Thank you for offer the code. I was runing the server and client codes on a group of remote machines. I wrote a powershell script to SSH into the server and client machines to start the python codes.
It seems the python codes freezes/hang the SSH every time. May I ask what is causing that and if there is a way around it? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment