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.