Socket: Netzwerk-Endpunkte einfach erklärt
Du lernst, wie Programme über Sockets Daten austauschen, ihre Zugänge adressieren und typische Fehler beim Empfangen vermeiden.
Kurz gesagt
Ein Socket ist ein Zugang zur Netzwerkkommunikation, den das Betriebssystem, die Verwaltungssoftware des Geräts, für ein Programm bereitstellt. Seine Adresse auf dem eigenen Gerät besteht hier aus Netzwerkadresse und Portnummer zur Zuordnung des Datenverkehrs, sobald sie festgelegt ist.
Programme können über ein Netz miteinander kommunizieren. Dafür nutzen sie Sockets und wählen Regeln für die Übertragung. Hier betrachten wir Sockets für IP: IP steht für Internet Protocol, ein Regelwerk zur Adressierung von Netzwerkanschlüssen und zur Weiterleitung von Daten.
Deine Lernziele
Ein Socket ist ein vom Betriebssystem verwalteter Zugang zur Netzwerkkommunikation. Man nennt ihn auch Endpunkt: Er bildet die Seite eines Programms bei der Kommunikation. Ein Socket kann zum Beispiel auf neue Verbindungen warten oder dem Austausch von Daten dienen. Ein Programm kann mehrere Sockets nutzen.
Eine IP-Adresse bezeichnet einen Netzwerkanschluss eines Geräts. Eine Portnummer kennzeichnet einen nummerierten Programmzugang auf diesem Gerät. Zusammen bilden IP-Adresse und Portnummer die lokale Adresse eines IP-Sockets. Lokal bedeutet hier: auf dem eigenen Gerät. Die Portnummer legt nicht die Übertragungsart fest; diese wird zusätzlich gewählt.
In unseren Beispielen trennt ein Doppelpunkt IP-Adresse und Portnummer. Bei 127.0.0.1:46210 ist 127.0.0.1 die IP-Adresse und 46210 die Portnummer. Die besondere IP-Adresse 127.0.0.1 führt zum eigenen Gerät. Ein daran gebundener Dienst, also ein angebotener Programmzugang, ist über diese Adresse vom selben Gerät aus erreichbar. Andere Geräte erreichen ihn über diese Adresse nicht.
Ein neu erzeugter Socket hat noch keine vollständig festgelegte lokale Adresse. Erst bei seiner weiteren Verwendung wird sie festgelegt. Die lokale Adresse beschreibt außerdem noch keine ganze Verbindung: Dazu gehören auch die Adresse der Gegenseite und die gewählte Übertragungsart.
Socket
Ein Socket ist ein vom Betriebssystem verwalteter Endpunkt für die Netzwerkkommunikation eines Programms.
Beispiel: Zwei ausgedachte Dienste auf demselben Gerät
- 1Der erste Dienst nutzt die lokale Adresse 127.0.0.1:46210.
- 2Der zweite Dienst nutzt die lokale Adresse 127.0.0.1:46211.
- 3Beide Adressen führen zum eigenen Gerät. Die verschiedenen Portnummern unterscheiden die beiden Programmzugänge.
Teste dich
Ein Transportprotokoll legt Regeln für die Datenübertragung zwischen Programmen fest. TCP steht für Transmission Control Protocol. Es arbeitet mit einer Verbindung, die vor dem Datenaustausch aufgebaut wird. Danach können beide Seiten gleichzeitig senden und empfangen.
TCP überträgt einen geordneten Datenstrom. Das ist eine Folge von Bytes ohne erhaltene Grenzen zwischen den gesendeten Nachrichten. Ein Byte besteht aus acht Bits; jedes Bit hat den Wert 0 oder 1. Zwei getrennt abgeschickte Textstücke müssen deshalb nicht in zwei getrennten Empfangsergebnissen erscheinen.
Daten werden im Netz in Paketen transportiert, also in begrenzten Einheiten. Gehen Pakete verloren, versucht TCP sie erneut zu übertragen. Die empfangenen Bytes werden in der richtigen Reihenfolge bereitgestellt. Bei einem dauerhaften Netzfehler kann die Übertragung jedoch mit einem Fehler enden. Zuverlässigkeit bedeutet hier keine sichere Zustellung trotz jedes Ausfalls.
UDP steht für User Datagram Protocol. Es benötigt keinen Verbindungsaufbau wie TCP. UDP überträgt Datagramme: einzelne Nachrichten mit erhaltenen Grenzen. Ein Datagramm kann fehlen, später als ein danach gesendetes Datagramm oder doppelt ankommen. UDP sorgt nicht selbst dafür, dass verlorene Datagramme erneut gesendet werden.
| Eigenschaft | TCP | UDP |
|---|---|---|
| Verbindung | Aufbau vor dem Datenaustausch | Kein Verbindungsaufbau nötig |
| Form der Daten | Geordneter Datenstrom ohne Nachrichtengrenzen | Getrennte Datagramme mit Nachrichtengrenzen |
| Verlust | Erneute Übertragung wird versucht; endgültiger Fehler ist möglich | Verlorene Datagramme werden nicht selbstständig erneut gesendet |
| Reihenfolge | Empfangene Bytes werden geordnet bereitgestellt | Datagramme können vertauscht oder doppelt ankommen |
Merke: TCP schützt die Reihenfolge der gelieferten Daten. Es macht aus zwei Sendungen aber nicht automatisch zwei empfangene Nachrichten. UDP erhält Nachrichtengrenzen, garantiert jedoch keine Zustellung.
Teste dich
Ein Client ist ein Programm, das eine Verbindung zu einem angebotenen Dienst anfordert. Ein Server ist ein Programm, das diesen Dienst anbietet. Beide Programme können auch auf demselben Gerät laufen. Jede Seite behält ihre eigenen Sockets.
Die folgenden Aufrufnamen beziehen sich auf Python 3, eine Programmiersprache. Ein Aufruf löst eine Programmaktion aus. Die Darstellung beschreibt den Ablauf und ist kein ausführbarer Programmcode; benötigte Angaben werden meist weggelassen.
Der Server erzeugt mit socket() einen Socket. Mit bind() bindet er ihn an eine lokale Adresse: Er legt seine IP-Adresse und Portnummer fest. listen() versetzt diesen Socket in den lauschenden Zustand. Er ist damit für neue Verbindungswünsche bereit.
Der Client erzeugt ebenfalls einen Socket. Mit connect() fordert er eine Verbindung zur Serveradresse an. Der Server übernimmt eine eingehende Verbindung mit accept(). Dieser Aufruf liefert einen neuen, verbundenen Socket für den Datenaustausch mit diesem Client. Der bisherige lauschende Socket bleibt für weitere Verbindungen erhalten. Über ihn werden keine Daten dieser Verbindung ausgetauscht.
Über die verbundenen Sockets übergibt send() Daten zum Senden, und recv() liest empfangene Daten. Einzelne Aufrufe müssen nicht alle vorgesehenen Bytes verarbeiten. Mehrere verbundene Server-Sockets können dieselbe lokale Adresse haben; ihre jeweiligen Gegenstellen unterscheiden die Verbindungen.
Nach dem Austausch schließen beide Seiten ihre verbundenen Sockets mit close(). Den lauschenden Socket schließt der Server, wenn er keine weiteren Verbindungen annehmen soll. Scheitert der Verbindungsaufbau oder die Übertragung, muss das Programm den Fehler behandeln.
Beispiel: Ein ausgedachter lokaler Hinweisserver
- 1Der Server erzeugt einen Socket und bindet ihn mit bind() an 127.0.0.1:48600.
- 2Mit listen() macht er diesen Socket für Verbindungswünsche bereit.
- 3Ein Client auf demselben Gerät erzeugt einen eigenen Socket und ruft connect() mit der Serveradresse auf.
- 4accept() liefert dem Server einen neuen, verbundenen Socket. Über diesen Socket tauscht er mit dem Client Daten aus.
- 5Nach dem Austausch schließen beide Seiten ihre verbundenen Sockets. Der lauschende Socket kann für weitere Clients offen bleiben.
Merke: Der lauschende TCP-Socket nimmt Verbindungswünsche entgegen. Der durch accept() erhaltene Socket dient dem Datenaustausch mit einem bestimmten Client.
Teste dich
Bei einem TCP-Socket in Python 3 liest recv(n) höchstens n Bytes. n ist die angegebene maximale Empfangsmenge. Der Aufruf kann weniger Bytes liefern, obwohl später weitere folgen. Ebenso können Daten aus mehreren Sendungen gemeinsam ankommen. Die Aufteilung auf einzelne Empfangsaufrufe ist nicht vorher festgelegt.
Das Programm braucht deshalb eine Regel zum Erkennen vollständiger Nachrichten. Es kann zum Beispiel eine feste Nachrichtenlänge, ein vereinbartes Trennzeichen oder eine vorangestellte Längenangabe verwenden. Bei einer festen Länge sammelt es empfangene Bytes, zählt sie und empfängt bei Bedarf weiter. Ein vorzeitiges Verbindungsende oder ein Fehler darf nicht als vollständige Nachricht behandelt werden. Auch send() kann weniger Bytes zum Senden übernehmen, als übergeben wurden; dann muss das Programm den verbleibenden Teil bearbeiten.
Für die ausgedachten Textbeispiele ist vereinbart: Jeder gezeigte Buchstabe von A bis Z belegt genau ein Byte. So lässt sich die empfangene Menge an den Buchstaben abzählen. Diese Vereinbarung gilt für unsere Beispiele und nicht allgemein für beliebige Texte.
Bei UDP betrachten wir den gewöhnlichen Betrieb ohne besonders aktivierte Funktionen, die mehrere Datagramme beim Empfang bündeln. In diesem Betrieb liefert ein Empfangsaufruf höchstens ein Datagramm. Ein Empfangspuffer ist ein bereitgestellter Speicherbereich für ankommende Daten. Ist er zu klein, kann das Datagramm abgeschnitten werden. Ein größerer Puffer fügt dagegen keine getrennten Datagramme zu einer gemeinsamen Nachricht zusammen.
Auch ein UDP-Socket kann connect() verwenden. Dabei wird ein Standardziel gesetzt, also eine voreingestellte Zieladresse. Das ist kein TCP-artiger Verbindungsaufbau und erzeugt keine Zustellgarantie. Ein an dieses Ziel gesendetes Datagramm kann weiterhin verloren gehen.
Beispiel: Ein möglicher TCP-Empfang in einer ausgedachten Übung
- 1Vereinbart sind fünf Bytes pro Nachricht. Gesendet wird „LAMPE“, wobei jeder Buchstabe ein Byte belegt.
- 2recv(5) könnte zunächst „LA“ liefern. Zwei Bytes sind da, drei fehlen.
- 3recv(3) könnte danach „MPE“ liefern. Zusammengesetzt ergibt sich „LAMPE“ mit fünf Bytes.
- 4Das ist eine mögliche Aufteilung bei erfolgreicher Übertragung, keine Vorhersage für einen echten Ablauf.
Merke: Die Zahl in recv(n) ist bei TCP eine Höchstmenge und keine Zusage. Prüfe die vereinbarte Nachrichtenlänge. Verwechsle außerdem ein UDP-Standardziel nicht mit einer Zustellgarantie.
Teste dich
Alles auf einen Blick
Socket
IP-Adresse und Portnummer bilden hier die lokale Socket-Adresse, sobald sie festgelegt ist. Die Übertragungsart wird zusätzlich gewählt.
Empfangene Bytes werden geordnet bereitgestellt. Verlorene Pakete werden erneut übertragen, doch dauerhafte Netzfehler können die Übertragung scheitern lassen.
Datagramme haben Nachrichtengrenzen, können aber fehlen, vertauscht oder doppelt ankommen.
Der lauschende Socket bleibt für Verbindungswünsche bereit. accept() liefert einen verbundenen Socket für den Datenaustausch.
Ein einzelnes recv() muss keine vollständige TCP-Nachricht liefern. Das Programm braucht eine Regel zum Erkennen ihrer Grenze.
Eine TCP-Nachricht in einer ausgedachten Übung zusammensetzen
- 1Vereinbarung: Jede Nachricht umfasst acht Bytes. Jeder gezeigte Buchstabe belegt ein Byte. Gesendet wird „BAUSTEIN“.
- 2In dieser möglichen Ausführung liefert recv(8) zunächst „BAU“. Drei Bytes sind da, fünf fehlen.
- 3recv(5) liefert danach „ST“. Jetzt liegen insgesamt fünf Bytes vor, drei fehlen.
- 4recv(3) liefert anschließend „EIN“. Zusammengesetzt entsteht „BAUSTEIN“ mit acht Bytes.
- 5Die vereinbarte Länge ist erreicht, also ist diese Nachricht vollständig. Andere Aufteilungen wären ebenfalls möglich; bei einem vorzeitigen Ende oder Fehler wäre die Nachricht unvollständig.
Fehler finden
Fehler in Zeile 3Der Aufruf hat zwei statt der vereinbarten vier Bytes geliefert. Richtig: Die Nachricht ist erst teilweise empfangen; zwei Bytes fehlen noch.
Lückentext
Bei der lokalen Adresse 127.0.0.1:49120 bezeichnet die Zahl hinter dem Doppelpunkt die . Für eine Verbindung mit geordnetem Datenstrom und Wiederholung verlorener Pakete wählt ein Programm ; ein dauerhafter Netzfehler kann trotzdem zum Abbruch führen. Eine ausgedachte TCP-Nachricht umfasst sieben Bytes. Der erste Empfang liefert drei Bytes. Bis zur vollständigen Nachricht fehlen noch Bytes.