Transmitting live data through the Internet

Basically, when we want to transmit data between networked processes, two options are available:

  1. TCP: A "reliable" transport protocol with possiblely high transmission latencies. Reliability means that the operating systems will try to solve the transmission errors, if they happen, by using ARQ.
  2. UDP: An unreliable transport protocol with a minimal (best-effort) transmission latencies. Unreliability means that the operating system will not try to fix any transmission error, if they happen (including the re-ordering of the packets).

Because we are interested in minimizing the total latency as much as possible, we will use UDP.

Some socket stuff in Python


In [92]:
import socket

LISTENING_PORT = 8001

class UDP_receiver():
    # We use a context manager (https://docs.python.org/3/reference/datamodel.html#context-managers).
    def __enter__(self):
        '''Create an UDP socket and listen to it.'''
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        print("socket created")
        self.sock.bind(('', LISTENING_PORT))
        print(f"listening at {self.sock.getsockname()} ... ")
        return self

    def receive(self):
        '''Receive a datagram.'''
        (message, from_addr) = self.sock.recvfrom(1024) # Blocking operation, 1024 is the maximum expected payload size.
        print(f"received {message} from {from_addr}")
        return message
    
    def __exit__(self,ext_type,exc_value,traceback):
        '''Close the socket.'''
        self.sock.close()
        print("socket closed")

class UDP_sender():
    def __enter__(self):
        '''Create an UDP socket.'''
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        print("socket created")
        return self

    def send(self, message, destination):
        '''Send data.'''
        self.sock.sendto(message, destination)
        print(f"message {message} sent to destination {destination}")

    def __exit__(self,ext_type,exc_value,traceback):
        '''Close the socket.'''
        self.sock.close()
        print("socket closed")

def wait_for_a_message():
    with UDP_receiver() as receiver:
        message = receiver.receive().decode("utf-8")
        print(f"recived message = {message}")

def send_message():
    with UDP_sender() as sender:
        message = b"hello world!"
        destination = ('localhost', LISTENING_PORT)
        sender.send(message, destination)
        
import threading

threading.Thread(target=wait_for_a_message).start()
send_message()


socket created
listening at ('0.0.0.0', 8001) ... 
socket created
message b'hello world!' sent to destination ('localhost', 8001)received b'hello world!' from ('127.0.0.1', 51932)

recived message = hello world!
socket closed
socket closed

Notice that UDP is a datagram (independent packet) oriented protocol. The maximum packet size in UDP is 64 KB.