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_INET6ist das IPv6-Äquivalent.SOCK_STREAM– eine TCP-Verbindung, der zuverlässige Byte-Stream.SOCK_DGRAMist 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:
UDP-Sockets – Datagramme senden und empfangen.
TCP-Sockets – TCP-Client und -Server.
Sockets mit asyncio – alles oben Genannte, aber innerhalb einer
asyncio-Ereignisschleife.
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.