UDP-Broadcasts

UDP Broadcasts

User Datagram Protocol (UDP)

UDP ist ein Netzwerkprotokoll der Transportschicht (wie TCP).

Vergleich mit TCP:

TCP

UDP

verbindungsorientiert (Drei-Wege-Handshake)

verbindungslos

zuverlässig (Übertragung der Pakete in richtiger Reihenfolge wird gesichert)

nicht zuverlässig (Pakete können verloren gehen, doppelt oder unsortiert ankommen)

Pakete werden ggf. neu gesendet

Pakete werden nicht neu gesendet

Vergleichsweise großer Header

Vergleichsweise kleiner Header

Anwendungsgebiete:

UDP-Broadcasts

UDP-Broadcasts können verwendet werden, damit sich Client und Server in einem Subnetz finden, ohne zunächst zu wissen, auf welchen Hosts sie laufen. Der Server öffnet dazu einen Socket, der auf einem bestimmten Port lauscht. Der Client kann dann einen UDP-Broadcast auf diesen Port an alle Hosts im Subnetz schicken, worauf der Server antworten kann.

Ein einfacher UDP-Server, der auf alle Anfragen den String "hello" zurückschickt:

   1 from SocketServer import UDPServer, BaseRequestHandler
   2 
   3 class Handler(BaseRequestHandler):
   4     def handle(self):
   5         print "message:", self.request[0]
   6         print "from:", self.client_address
   7         socket = self.request[1]
   8         socket.sendto("hello", self.client_address)
   9 
  10 
  11 addr = ("", 5555)
  12 print "listening on %s:%s" % addr
  13 server = UDPServer(addr, Handler)
  14 server.serve_forever()

Wichtig ist, dass der Socket an den leeren String gebunden wird, das entspricht INADDR_ANY und bedeutet, dass von beliebigen Hosts empfangen wird. (Anmerkung: Funktioniert so nur bei IPv4).

Der Client broadcastet dann wie folgt, in diesem Beispiel sendet er ebenfalls den String "hello" an den Server:

   1 import socket
   2 
   3 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
   4 s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
   5 s.settimeout(5)
   6 
   7 s.sendto("hello", ("<broadcast>", 5555))
   8 try:
   9     print "Response: %s" % s.recv(1024)
  10 except socket.timeout:
  11     print "No server found"
  12 
  13 s.close()

Hier ist wichtig, an <broadcasts>, also INADDR_BROADCAST zu senden. (Anmerkung: Funktioniert so nur bei IPv4). Man kann die Broadcastadresse auch manuell setzen.

Über die UDP-Verbindung können die beiden Komponenten z.B. ihre Hostnamen austauschen, um dann eine TCP-Verbindung aufzubauen.

Beispiel: Programm, das autmatisch zu Server oder Client wird

Hier ist ein Beispiel für ein Programm, dass beim Start versucht, Kontakt zu einem schon vorhandenen Server aufzunehmen. Kommt kein solcher Kontakt zu stande, wird das Programm selbst zum Server, andernfalls wird es zum Client. Über die UDP-Nachrichten werden weitere Informationen ausgetauscht und geprüft, ob wir auch mit "unserem" Server/Client sprechen und nicht mit Programmen, die zufällig den gleichen Port benutzen.

   1 import socket
   2 import threading
   3 from SocketServer import UDPServer, BaseRequestHandler
   4 
   5 PORT = 55555
   6 
   7 
   8 class MasterUDPServer(threading.Thread):
   9     def run(self):
  10         addr = ("", PORT)
  11         print "UDP server listening on", addr
  12         server = UDPServer(addr, Handler)
  13         server.serve_forever()
  14 
  15 
  16 class Handler(BaseRequestHandler):
  17 
  18     number_client = 0
  19     my_addr = socket.getfqdn()
  20 
  21     def handle(self):
  22         request = self.request[0].strip()
  23         if request == "TEST": # is it our UDP client?
  24             Handler.number_client += 1
  25             print "Detected %i. client on %s" % (Handler.number_client,
  26                                                  self.client_address)
  27             socket = self.request[1]
  28             reply = "TEST %i %s" % (Handler.number_client, Handler.my_addr)
  29             socket.sendto(reply, self.client_address)
  30 
  31 
  32 if __name__ == "__main__":
  33     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
  34     s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
  35     s.settimeout(3)
  36 
  37     print "Trying to find server..."
  38     s.sendto("TEST", ("<broadcast>", PORT))
  39     try:
  40         response = s.recv(1024).strip()
  41         if not response.startswith("TEST"):
  42             raise ValueError() # it's not our UDP server
  43 
  44         print "Found server."
  45         (dummy, my_number, server_addr) = response.split()
  46         print "I am client number", my_number
  47         print "Server is on", server_addr
  48 
  49     except socket.timeout, ValueError:
  50         print "Could not find server, starting new server."
  51         udpserver = MasterUDPServer()
  52         udpserver.start()
  53 
  54     s.close()

Die Ausgabe beim ersten Start des Programmes sieht so aus:

$ ./udp_test.py
Trying to find server...
Could not find server, starting new server.
UDP server listening on ('', 55555)
Detected 1. client on ('nnn.nnn.168.44', 55896)
Detected 2. client on ('nnn.nnn.168.23', 32889)

Startet man das Programm nochmals, erhält man:

$ ./udp_test.py
Trying to find server...
Found server.
I am client number 1
Server is on somehost

$ ./udp_test.py
Trying to find server...
Found server.
I am client number 2
Server is on somehost

Weitere Möglichkeiten von UDP

UDP-hole-punching, um peer-to-peer-Verbindungen trotz Firewall zu ermöglichen.

macro::

Tags: Codesnippets | Netzwerk

UDP-Broadcasts (zuletzt geändert am 2018-06-23 13:12:34 durch anonym)