UDP python sockets programming

July 17, 2020

  • server1.jpg Back-End

Simple client - server

After binding a port number to server listening socket, udp protocol allow the client to use two types of commands for sending / receiving data to / from server:

  • using sendto-recvfrom
  • using connect + send-recv

For udp data packet transmitted, there is no (built in) way to verify if this reached the destination, except we design a procedure of response confirmation from the server side.

#udp_server.py

import socket

MAX = 1024
ADDR = ''  #all local interfaces
PORT = 1060

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.bind((ADDR, PORT))

print (s.getsockname(), "is waiting ...")

while True:
    data, address = s.recvfrom(MAX)
    print ("socket %s received %s bytes from %s" % (s.getsockname(),len(data),address))
    s.sendto('Your data was %d bytes' % len(data), address)
#udp_client.py

import socket

MAX = 1024
HOST = '127.0.0.1'
PORT = 1060

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

msg = ('0' * 10).encode('utf-8')

print "==== Using sendto-recvfrom ===="

s.sendto(msg, (HOST, PORT))
data, address = s.recvfrom(MAX)
print 'Client socket name is:', s.getsockname()
print 'Server is: ', address
print 'Server says: ', data

print "==== Using connect + send-recv ===="

s.connect((HOST, PORT))
print 'Client socket name is:', s.getsockname()
print 'Server is: ', s.getpeername()

s.send(msg)
data = s.recv(MAX)
print 'Server says: ', data

UDP broadcast

Udp protocol can deliver broadcast messages to all addresses of a local network.

#udp_server_broadcast.py

import socket

MAX = 1024
ADDR = ''  #all local interfaces
PORT = 1060

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

s.bind((ADDR, PORT))

print (s.getsockname(), "is waiting ...")

while True:
    data, address = s.recvfrom(MAX)
    print ("socket %s received %s bytes from %s" % (s.getsockname(),len(data),address))
    s.sendto('Your data was %d bytes' % len(data), address)
#udp_client_broadcast.py

import socket

MAX = 1024
HOST = '192.168.0.255'
PORT = 1060

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

msg = 'Broadcast message'

print "==== Using sendto-recvfrom ===="

s.sendto(msg, (HOST, PORT))
data, address = s.recvfrom(MAX)
print 'Client socket name is:', s.getsockname()
print 'Server is: ', address
print 'Server says: ', data

UDP multiplexing (non-blocking)

With non-blocking sockets, we could manage multiple sockets in the same time. Example below includes retry procedure for sending data to server in case of confirmation message is not received (server simulates randim data package loss)

#udp_server_multiplex.py

import select
import socket
import time
import random

MAX = 1024
ADDR = ''  #all local interfaces
PORT1 = 1060
PORT2 = 1061

s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.setblocking(0)
s1.bind((ADDR, PORT1))

s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2.setblocking(0)
s2.bind((ADDR, PORT2))

print (s1.getsockname(), 'and ' , s2.getsockname(), "are waiting ...")

read_list = [s1,s2]

while True:
    readable, writable, errored = select.select(read_list, [], [])
    for s in readable:
        if s == s1:
            data, address = s1.recvfrom(MAX)
            print ("socket %s received %s bytes from %s" % (s1.getsockname(),len(data),address))
            if(random.randint(0, 1)):
                s1.sendto('Your data was %d bytes' % len(data), address)
            else:
                print "Pretending that packet was lost: no response back"
        if s == s2:
            data, address = s2.recvfrom(MAX)
            print ("socket %s received %s bytes from %s" % (s2.getsockname(),len(data),address))
            if(random.randint(0, 1)):
                s2.sendto('Your data was %d bytes' % len(data), address)
            else:
                print "Pretending that packet was lost: no response back"
#udp_client_multiplex.py

import socket
import time

MAX = 1024
HOST = '127.0.0.1'
PORT1 = 1060
PORT2 = 1061

s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

msg = ('0' * 10).encode('utf-8')


def send1():
    print "==== Using sendto-recvfrom ===="

    try_nr = 1
    delay = 0.1
    while True:
        print try_nr
        try_nr = try_nr + 1
        s1.sendto(msg, (HOST, PORT1))
        s1.settimeout(delay)
        try:
            data, address = s1.recvfrom(MAX)
        except socket.timeout:
            delay *= 2 # wait even longer for the next request
            if delay > 2.0:
                raise RuntimeError('I think the server is down')
        except:
            raise # a real error, so we let the user see it
        else:
            break # we are done, and can stop looping

    #s1.sendto(msg, (HOST, PORT1))
    #data, address = s1.recvfrom(MAX)
    print 'Client socket name is:', s1.getsockname()
    print 'Server is: ', address
    print 'Server says: ', data


def send2():
    print "==== Using connect + send-recv ===="

    s2.connect((HOST, PORT2))
    print 'Client socket name is:', s2.getsockname()
    print 'Server is: ', s2.getpeername()

    try_nr = 1
    delay = 0.1
    while True:
        print try_nr
        try_nr = try_nr + 1
        s2.send(msg)
        s2.settimeout(delay)
        try:
            data = s2.recv(MAX)
        except socket.timeout:
            delay *= 2 # wait even longer for the next request
            if delay > 2.0:
                raise RuntimeError('I think the server is down')
        except:
            raise # a real error, so we let the user see it
        else:
            break # we are done, and can stop looping

    print 'Server says: ', data


while True:
    send1()
    time.sleep(1)
    send2()

Return to home