9.11. Socket-Objekte

Die Python-Schnittstelle zur Transportschicht ist die Klasse socket.socket. Ein Socket repräsentiert einen Endpunkt einer Netzwerkkonversation – eine Adresse, einen Port und das Protokoll (UDP oder TCP), über das die Konversation läuft. Die Kapitel zur Hardwaresteuerung haben UART-Instanzen geöffnet, um über eine Leitung zu kommunizieren; dieser Abschnitt öffnet socket-Instanzen, um über das Netzwerk zu kommunizieren. Die Form ist dieselbe; der zugrunde liegende Dienst ist nur deutlich leistungsfähiger.

9.11.1. Einen Socket erstellen

Drei Argumente beschreiben einen Socket: welche Adressfamilie er spricht, welchen Socket-Typ er bietet und welches Protokoll er verwendet. Die Standardwerte decken die Fälle ab, die der restliche Abschnitt verwendet:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)   # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # IPv4 UDP

Die beiden Konstanten, zwischen denen die Anwendung in fast jedem Fall wählt:

  • AF_INET – IPv4-Adressen (eine numerische IP plus ein Port). Die häufigste Wahl. AF_INET6 ist das IPv6-Äquivalent.

  • SOCK_STREAM – eine TCP-Verbindung, der zuverlässige Byte-Stream. SOCK_DGRAM ist das UDP-Äquivalent.

Das dritte Argument (das Protokoll) bleibt bei null, was anhand der ersten beiden den richtigen Standard auswählt. Der vollständige Konstruktor ist auf socket — socket-Modul dokumentiert.

9.11.2. Adressen an einem Socket

Eine Socket-Adresse ist ein Tupel aus (host, port):

("192.168.1.50", 80)
("0.0.0.0", 8000)

Der Host ist die IP-Adresse als String. Der Port ist die 16-Bit-Ganzzahl, die auf Ports behandelt wird.

Eine Handvoll spezieller Host-Strings sind es wert, gekannt zu werden:

  • "0.0.0.0" bedeutet „jede IPv4-Schnittstelle auf diesem Gerät“. Ein an diese Adresse gebundener Server akzeptiert Verbindungen auf jeder Adresse, die die Kamera besitzt.

  • "127.0.0.1" ist localhost – Verkehr dorthin verlässt das Gerät nie. Nützlich zum Testen.

  • "255.255.255.255" ist die lokale Broadcast-Adresse. Ein an sie gesendetes UDP-Datagramm geht an jedes Gerät im lokalen Segment.

Domainnamen wie "example.com" sind keine gültigen Host-Strings in einer Socket-Adresse. Sie müssen zuerst in eine IP aufgelöst werden; Namen und DNS behandelt den getaddrinfo()-Aufruf, der das tut.

9.11.3. Die beiden Rollen

Der Lebenszyklus eines Sockets hängt davon ab, auf welcher Seite der Konversation er sich befindet. Ein Client-Socket ruft connect() (oder, bei UDP, einfach sendto()) auf, um mit einem bekannten Server zu kommunizieren. Ein Server-Socket ruft bind() auf, um einen Port zu beanspruchen, und dann entweder listen() und accept() (bei TCP) oder recvfrom() (bei UDP), um eingehenden Verkehr zu empfangen.

Derselbe socket-Konstruktor wird in beiden Fällen verwendet; nur die danach aufgerufenen Methoden unterscheiden sich. Die nächsten drei Seiten gehen die praktischen Muster durch:

9.11.4. Einen Socket schließen

Jeder Socket hält ein kleines Stück Betriebssystem-Zustand (eine Port-Reservierung, Puffer, den TCP-Zustand der Verbindung). Wenn die Anwendung damit fertig ist, gibt close() diesen Zustand frei. Ein vergessener Socket ist ein langsames Leck, das sich summiert; in einer Schleife, die Verbindungen öffnet, wird ein fehlendes close irgendwann den Pool verfügbarer Sockets der Kamera erschöpfen.

Das sauberste Muster ist die with-Anweisung:

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(addr)
    s.send(b"GET / HTTP/1.0\r\n\r\n")
    ...
# socket is closed automatically here, even on error

Sockets implementieren das Kontextmanager-Protokoll, das in der Python-Übersicht behandelt wird, sodass der with-Block garantiert, dass close() aufgerufen wird, unabhängig davon, ob der Block normal oder durch Auslösen einer Ausnahme verlassen wurde.

9.11.5. Die socket-Referenz

Diese und die nächsten Seiten gehen die API in erzählerischer Form durch. Für die vollständige argumentbezogene Referenz jeder Methode, jedes Flags und jeder Konstante, die das Modul bereitstellt, siehe socket — socket-Modul. Die Referenz ist auch der Ort, um nach den weniger gebräuchlichen Operationen zu suchen (Socket-Optionen, Multicast-Gruppenmitgliedschaft, IPv6-Scope-IDs), die dieser Abschnitt nicht behandelt.