Transmission Control Protocol: Unterschied zwischen den Versionen
Zeile 67: | Zeile 67: | ||
Verbindung 2: (Lokaler Rechner, Port x, Entfernter Rechner, '''Port z''') | Verbindung 2: (Lokaler Rechner, Port x, Entfernter Rechner, '''Port z''') | ||
*Ein Serverprozess erzeugt beispielsweise einen Socket (''socket'', ''bind'') auf Port 80, markiert diesen für eingehende Verbindungen ( | *Ein Serverprozess erzeugt beispielsweise einen Socket (''socket'', ''bind'') auf Port 80, markiert diesen für eingehende Verbindungen ( ''listen'') und fordert vom Betriebssystem die nächste anstehende Verbindung an ( ''accept''). | ||
*Diese Anforderung blockiert den Serverprozess zunächst, da noch keine Verbindung existiert. | |||
*Kommt dann die erste Verbindungsanfrage durch einen Client an, wird sie vom Betriebssystem angenommen, so dass die Verbindung zustande kommt. | *Kommt dann die erste Verbindungsanfrage durch einen Client an, wird sie vom Betriebssystem angenommen, so dass die Verbindung zustande kommt. | ||
*Ab jetzt wird diese Verbindung durch das oben beschriebene Quadrupel identifiziert. | *Ab jetzt wird diese Verbindung durch das oben beschriebene Quadrupel identifiziert. |
Version vom 15. März 2021, 09:25 Uhr
Das Transmission Control Protocol (TCP, Übertragungssteuerungsprotokoll) ist ein Netzwerkprotokoll, das definiert, auf welche Art und Weise Daten zwischen Netzwerkkomponenten ausgetauscht werden sollen.
Geschichte
- Entwickelt von Robert E. Kahn und Vinton G. Cerf als Forschungsarbeit.
- Beginn 1973, erste Standardisierung 1981 als RFC 793.
- Danach gab es viele Erweiterungen, diese werden bis heute in RFCs spezifiziert.
Was ist TCP
- Ist ein zuverlässiges, verbindungsorientiertes, paketvermitteltes (nicht paketvermittelnd) Transportprotokoll.
- Ist eine Implementierung der Transportschicht.
- Fast alle aktuelle Betriebssysteme beherrschen TCP (Nutzung für Datenaustausch mit anderen Rechnern)
- Ist ein sehr weit verbreitetes Protokoll zur Datenübertragung.
- Es ist Teil der Internetprotokollfamilie (der Grundlage des Internet).
- Im Unterschied zum verbindungslosen User Datagram Protokoll (UDP) stellt TCP eine Verbindung zwischen zwei Endpunkten einer Netzverbindung (Sockets) her.
- Auf dieser Verbindung können in beide Richtungen Daten übertragen werden.
Vorteile
- Datenverluste werden erkannt und automatisch behoben
- Datenübertragung ist in beiden Richtungen möglich
- Netzüberlastung wird verhindert
Aufgabe
- Die Aufgabe von TCP ist es nicht, Pakete zu übertragen, sondern die Bytes eines Datenstroms.
- Die Paketvermittlung wird durch das Internetprotokoll bereitgestellt.
- IP ist paketvermittelnd, aber TCP paketvermittelt.
in Zuordnung
- TCP setzt (meistens) auf das Internet-Protokoll auf, weshalb häufig (oft nicht ganz korrekt) auch vom „TCP/IP-Protokoll“ die Rede ist.
- In Protokollstapeln wie dem OSI-Modell sind TCP und IP nicht auf derselben Schicht angesiedelt.
- TCP wird als fast ausschließliches Transportmedium für das World Wide Web, E-Mail und viele andere populäre Netzdienste verwendet.
in Kürzung
Allgemeines
- TCP ist im Prinzip eine Ende-zu-Ende-Verbindung in Vollduplex.
- Kann auch als zwei Halbduplexverbindungen betrachtet werden (Informationsfluss in beide Richtungen (allerdings nicht gleichzeitig)).
- Die Daten in Gegenrichtung können zusätzliche Steuerungsinformationen enthalten.
- Die TCP-Software übernimmt Verbindungsverwaltung sowie die Datenübertragung.
- Die TCP-Software ist üblicherweise im Netz-Protokollstack des Betriebssystems angesiedelt.
- Anwendungsprogramme benutzen eine Schnittstelle dazu (meist Sockets) die sich (Betriebssystem unterschiedlich) beispielsweise bei Microsoft Windows in extra einzubindenden Programmbibliotheken („Winsock.dll“ bzw. „wsock32.dll“) befinden.
- Linux und andere unixoide Betriebssysteme enthalten einen Socketlayer im Betriebssystemkern.
- Zugriff auf den Socketlayer über Systemaufrufe.
- Anwendungen, die TCP häufig nutzen, sind zum Beispiel Webbrowser und Webserver.
TCP-Verbindung
- Jede TCP-Verbindung wird eindeutig durch zwei Endpunkte identifiziert.
- Ein Endpunkt stellt ein geordnetes Paar dar (IP-Adresse und Port).
- Ein solches Paar bildet eine bidirektionale Software-Schnittstelle (bez. auch als Socket).
TCP-Verbindungen werden durch vier Werte (einem Quadrupel) identifiziert:
(Lokaler Rechner, Port x, Entfernter Rechner, Port y)
Dabei kommt es auf das gesamte Quadrupel an, das heißt:
- Es können zwei verschiedene Prozesse auf demselben Rechner denselben lokalen Port benutzen und mit demselben Rechner auf der Gegenseite kommunizieren, sofern die beteiligten Prozesse auf der anderen Seite unterschiedliche Ports benutzen.
- In einem solchen Fall würde es sich um zwei verschiedene Verbindungen handeln, deren Quadrupel sich nur in einem von vier Werten unterscheidet: dem Port der Gegenseite.
Verbindung 1: (Lokaler Rechner, Port x, Entfernter Rechner, Port y) Verbindung 2: (Lokaler Rechner, Port x, Entfernter Rechner, Port z)
- Ein Serverprozess erzeugt beispielsweise einen Socket (socket, bind) auf Port 80, markiert diesen für eingehende Verbindungen ( listen) und fordert vom Betriebssystem die nächste anstehende Verbindung an ( accept).
- Diese Anforderung blockiert den Serverprozess zunächst, da noch keine Verbindung existiert.
- Kommt dann die erste Verbindungsanfrage durch einen Client an, wird sie vom Betriebssystem angenommen, so dass die Verbindung zustande kommt.
- Ab jetzt wird diese Verbindung durch das oben beschriebene Quadrupel identifiziert.
- Schließlich wird der Serverprozess aufgeweckt und ihm ein Handle für diese Verbindung überreicht.
- Üblicherweise startet der Serverprozess anschließend einen Kindprozess, zu dem er die Behandlung der Verbindung delegiert.
- Er selbst setzt dann seine Arbeit mit einer weiteren Accept-Anforderung an das Betriebssystem fort.
- Dadurch ist es möglich, dass ein Webserver mehrere Verbindungen von verschiedenen Rechnern annehmen kann.
Ports
- Ports sind Dualsystem 16-Bit-Zahlen (Portnummern) und reichen von 0 bis 65535.
- Ports von 0 bis 1023 sind reserviert und werden von der Internet Assigned Numbers Authority (IANA) vergeben, z.B. ist Port 80 für Hypertext Transfer Protocol (HTTP) reserviert.
- Das Benutzen der vordefinierten Ports ist nicht bindend.
- So kann jeder Administrator beispielsweise einen FTP-Server (normalerweise Port 21) auch auf einem beliebigen anderen Port laufen lassen.
- Üblicherweise bestimmt das Programm auf der Clientseite den Port nicht selbst, sondern lässt ihn sich vom Betriebssystem zuweisen.
- Mehrfaches listen auf demselben Port ist nicht möglich.
Verbindungsaufbau und -abbau
Ein Server, der seinen Netzwerkdienst Dienst anbietet, erzeugt einen Endpunkt (Socket) mit der Portnummer und seiner IP-Adresse. Dies wird als passive open oder auch als listen bezeichnet.
Will ein Client eine Verbindung aufbauen, erzeugt er einen eigenen Socket aus seiner Rechneradresse und einer eigenen, noch freien Portnummer. Mit Hilfe eines ihm bekannten Ports und der Adresse des Servers kann dann eine Verbindung aufgebaut werden. Eine TCP-Verbindung ist durch folgende 4 Werte eindeutig identifiziert:
- Quell-IP-Adresse
- Quell-Port
- Ziel-IP-Adresse
- Ziel-Port
Während der Datenübertragungsphase ( active open) sind die Rollen von Client und Server (aus TCP-Sicht) vollkommen symmetrisch. Insbesondere kann jeder der beiden beteiligten Rechner einen Verbindungsabbau einleiten.
Halb geschlossene Verbindungen
Der Verbindungsabbau kann auf zwei Arten erfolgen: beidseitig oder schrittweise einseitig. Bei letzterer Variante spricht man von einer halb geschlossenen Verbindung (nicht zu verwechseln mit halb offenen Verbindungen, siehe unten). Sie erlaubt der Gegenseite nach der einseitigen Trennung noch Daten zu übertragen.
Halb geschlossene Verbindungen sind ein Erbe des Betriebssystems Unix , in dessen Umfeld TCP entstanden ist. Entsprechend dem Grundsatz everything is a file (dt. „Alles ist eine Datei“) unterstützt Unix bei TCP-Verbindungen eine zu Pipe (Informatik) Pipes völlig analoge Interaktion zweier Prozesse: für ein Programm soll es schlichtweg irrelevant sein, ob es von einer TCP-Verbindung oder einer Datei liest. Ein Unix-Programm liest typischerweise bis zum Ende der Standardeingabe und schreibt anschließend das Verarbeitungsergebnis in die Standardausgabe. Die Standard-Datenströme werden vor Ausführung des Programms mit Dateien verbunden.
Die Hin- und Rückkanäle einer TCP-Verbindung werden mit Standardein- und -ausgabe verbunden und somit logisch als je eine Datei repräsentiert. Eine geschlossene Verbindung wird dem lesenden Prozess als erreichtes Dateiende übersetzt. Das angesprochene typische Unix-Verarbeitungsschema setzt voraus, dass die Verbindung in Rückrichtung nach dem Lesen des Dateiendes noch zum Schreiben bereitsteht, woraus der Bedarf für halb geschlossene Verbindungen resultiert.
Halb offene Verbindungen
Eine Verbindung ist halb offen, wenn eine Seite abstürzt, ohne dass die verbleibende Seite dies erfährt. Dies hat den unerwünschten Effekt, dass Betriebssystemressourcen nicht freigegeben werden. Halb offene Verbindungen können entstehen, weil TCP-Verbindungen von Protokollseite solange bestehen, bis sie abgebaut werden. Häufig werden jedoch von Anwendungsseite entsprechende Vorkehrungen getroffen.
Verbindungsaufbau
Der Client, der eine Verbindung aufbauen will, sendet dem Server ein SYN-Paket (von enS synchronize) mit einer Sequenznummer x. Die Sequenznummern sind dabei für die Sicherstellung einer vollständigen Übertragung in der richtigen Reihenfolge und ohne Duplikate wichtig. Es handelt sich also um ein Paket, dessen SYN-Bit im Paketkopf gesetzt ist (siehe #Aufbau des TCP-Headers TCP-Header ). Die Start-Sequenznummer ist eine beliebige Zahl, deren Generierung von der jeweiligen TCP-Implementierung abhängig ist. Sie sollte jedoch möglichst Zufallszahl zufällig sein, um Sicherheitsrisiken zu vermeiden.
Der Server (siehe Skizze) empfängt das Paket. Ist der Port geschlossen, antwortet er mit einem TCP-RST, um zu signalisieren, dass keine Verbindung aufgebaut werden kann. Ist der Port geöffnet, bestätigt er den Erhalt des ersten SYN-Pakets und stimmt dem Verbindungsaufbau zu, indem er ein SYN/ACK-Paket zurückschickt ( ACK (Signal) ACK von engl. acknowledgement ‚Bestätigung‘). Das gesetzte ACK-Flag im TCP-Header kennzeichnet diese Pakete, welche die Sequenznummer x+1 des SYN-Pakets im Header enthalten. Zusätzlich sendet er im Gegenzug seine Start-Sequenznummer y, die ebenfalls beliebig und unabhängig von der Start-Sequenznummer des Clients ist.
Der Client bestätigt zuletzt den Erhalt des SYN/ACK-Pakets durch das Senden eines eigenen ACK-Pakets mit der Sequenznummer x+1. Dieser Vorgang wird auch als „Forward Acknowledgement“ bezeichnet. Aus Sicherheitsgründen sendet der Client den Wert y+1 (die Sequenznummer des Servers + 1) im ACK-Segment zurück. Die Verbindung ist damit aufgebaut. Im folgenden Beispiel wird der Vorgang abstrakt dargestellt:
1. | SYN-SENT | → | <SEQ=100><CTL=SYN> | → | SYN-RECEIVED |
2. | SYN/ACK-RECEIVED | ← | <SEQ=300><ACK=101><CTL=SYN,ACK> | ← | SYN/ACK-SENT |
3. | ACK-SENT | → | <SEQ=101><ACK=301><CTL=ACK> | → | ESTABLISHED |
Einmal aufgebaut, ist die Verbindung für beide Kommunikationspartner gleichberechtigt, man kann einer bestehenden Verbindung auf TCP-Ebene nicht ansehen, wer der Server und wer der Client ist. Daher hat eine Unterscheidung dieser beiden Rollen in der weiteren Betrachtung keine Bedeutung mehr.
Verbindungsabbau
Der geregelte Verbindungsabbau erfolgt ähnlich. Statt des SYN-Bits kommt das FIN-Bit (von engl. finish ‚Ende‘, ‚Abschluss‘) zum Einsatz, welches anzeigt, dass keine Daten mehr vom Sender kommen werden. Der Erhalt des Pakets wird wiederum mittels ACK bestätigt. Der Empfänger des FIN-Pakets sendet zuletzt seinerseits ein FIN-Paket, das ihm ebenfalls bestätigt wird.
Zudem ist ein verkürztes Verfahren möglich, bei dem FIN und ACK genau wie beim Verbindungsaufbau im selben Paket untergebracht werden. Die maximum segment lifetime (MSL) ist die maximale Zeit, die ein Segment im Netzwerk verbringen kann, bevor es verworfen wird. Nach dem Senden des letzten ACKs wechselt der Client in einen zwei MSL andauernden Wartezustand ( wait state), in dem alle verspäteten Segmente verworfen werden. Dadurch wird sichergestellt, dass keine verspäteten Segmente als Teil einer neuen Verbindung fehlinterpretiert werden können. Außerdem wird eine korrekte Verbindungsterminierung sichergestellt. Geht ACK y+1 verloren, läuft beim Server der Timer ab, und das LAST_ACK-Segment wird erneut übertragen.
Puffer
Beim Versenden von Daten über das TCP werden zwei Puffer (Informatik) Puffer verwendet. Senderseitig übermittelt die Applikation die zu sendenden Daten an das TCP und dieses puffert die Daten, um mehrere kleine Übertragungen effizienter in Form einer einzigen großen zu senden. Nachdem die Daten dann an den Empfänger übermittelt wurden, landen sie im empfängerseitigen Puffer. Dieser verfolgt ähnliche Ziele. Wenn vom TCP mehrere einzelne Pakete empfangen wurden, ist es besser, diese zusammengefügt an die Applikation weiterzugeben.
Drei-Wege-Handschlag
Sowohl beim Verbindungsaufbau als auch beim Verbindungsabbau werden die Antworten auf das erste SYN- bzw. FIN-Paket typischerweise zu einem einzelnen Paket (SYN/ACK bzw. FIN/ACK) zusammengefasst – theoretisch wäre auch das Versenden zweier separater Pakete denkbar. Da in diesem Fall nur noch drei Pakete versendet werden müssen, spricht man auch häufig vom sogenannten Drei-Wege-Handschlag . Das Zusammenfassen des FIN-Pakets und des ACK-Pakets ist allerdings problematisch, da das Senden eines FIN-Pakets die Bedeutung hat „es folgen keine weiteren Daten mehr“. Allerdings kann der Sender des FIN-Pakets weiterhin Daten empfangen (wollen); man spricht von einer halb geschlossenen Verbindung (die Empfangsrichtung ist weiterhin offen, während die Senderichtung geschlossen wurde). Es wäre z. B. denkbar, den Beginn einer HTTP-Anfrage (HTTP-Request) direkt im SYN-Paket mitzuschicken, weitere Daten, sobald die Verbindung aufgebaut wurde, und im letzten HTTP-Request-Paket die (Senderichtung der) Verbindung gleich mittels FIN zu schließen. In der Praxis wird dieses Verfahren allerdings nicht angewendet. Würde der Browser die Verbindung auf diese Art sofort schließen, würde möglicherweise auch der Server die Verbindung schließen anstatt die Anfrage vollständig zu beantworten.
Aufbau des TCP-Headers
Allgemeines
Das TCP-Segment besteht immer aus zwei Teilen: dem Header und der Nutzlast (enS payload). Die Nutzlast enthält die zu übertragenden Daten, die wiederum Protokollinformationen der Anwendungsschicht, wie Hypertext Transfer Protocol HTTP oder File Transfer Protocol FTP , entsprechen können. Der Header enthält für die Kommunikation erforderliche Daten sowie die Dateiformat-beschreibende Information. Den schematischen Aufbau des TCP-Headers kann man in Abbildung 5 sehen. Da das Options-Feld in der Regel nicht genutzt wird, hat ein typischer Header eine Größe von 20 Byte. Die Werte werden in der Byte-Reihenfolge Big-Endian angegeben.
Erläuterung
- Source Port (Quellport) (2 Byte)
- Gibt die Portnummer auf der Senderseite an.
- Destination Port (Zielport) (2 Byte)
- Gibt die Portnummer auf der Empfängerseite an.
- Sequence Number (4 Byte)
- Sequenznummer des ersten Daten- Oktett (Informatik) Oktetts (Byte) dieses TCP-Pakets oder die Initialisierungs-Sequenznummer falls das SYN-Flag gesetzt ist. Nach der Datenübertragung dient sie zur Sortierung der TCP-Segmente, da diese in unterschiedlicher Reihenfolge beim Empfänger ankommen können.
- Acknowledgement Number (Quittierungsnummer) (4 Byte)
- Sie gibt die Sequenznummer an, die der Absender dieses TCP-Segmentes als Nächstes erwartet. Sie ist nur gültig, falls das ACK (Signal) ACK-Flag gesetzt ist.
- Data Offset (4 Bit)
- Länge des TCP-Headers in 32-Bit-Blöcken – ohne die Nutzdaten (Payload). Hiermit wird die Startadresse der Nutzdaten angezeigt.
- Reserved (4 Bit)
- Das Reserved-Feld ist für zukünftige Verwendungen reserviert. Alle Bits müssen null sein.
- Control- Flag (Informatik) Flags (8 Bit)
- Sind zweiwertige Variablen mit den möglichen Zuständen gesetzt und nicht gesetzt, die zur Kennzeichnung bestimmter für die Kommunikation und Weiterverarbeitung der Daten wichtiger Zustände benötigt werden. Im Folgenden werden die Flags des TCP-Headers und die von ihrem Zustand abhängigen, auszuführenden Aktionen beschrieben.
- CWR und ECE
- sind zwei Flags, die für Explicit Congestion Notification (ECN) benötigt werden. Mit gesetztem ECE-Bit (ECN-Echo) teilt der Empfänger dem Sender mit, dass das Netzwerk überlastet ist und die Senderate reduziert werden muss. Hat der Sender das getan, teilt er dies dem Empfänger durch Setzen des CWR-Bit ( Congestion Window Reduced) mit.
- URG
- Ist das Urgent-Flag (urgent = dringend) gesetzt, so werden die Daten nach dem Header sofort von der Anwendung bearbeitet. Dabei unterbricht die Anwendung die Verarbeitung der Daten des aktuellen TCP-Segments und liest alle Bytes nach dem Header bis zu dem Byte, auf das das Urgent- Zeiger (Informatik) Pointer -Feld zeigt, aus. Dieses Verfahren ist fern verwandt mit einem Softwareinterrupt . Dieses Flag kann zum Beispiel verwendet werden, um eine Anwendung auf dem Empfänger abzubrechen. Das Verfahren wird nur äußerst selten benutzt, Beispiele sind die bevorzugte Behandlung von CTRL-C (Abbruch) bei einer Terminalverbindung über Remote login rlogin oder telnet .
- In der Regel wird dieses Flag nicht ausgewertet.
- ACK
- Das Acknowledgment-Flag hat in Verbindung mit der Acknowledgment-Nummer die Aufgabe, den Empfang von TCP-Segmenten beim Datentransfer zu bestätigen. Die Acknowledgment-Nummer ist nur gültig, wenn das Flag gesetzt ist.
- PSH
- RFC 1122 und RFC 793 spezifizieren das Push-Flag so, dass bei gesetztem Flag sowohl der ausgehende, als auch der eingehende Puffer übergangen wird. Da man bei TCP keine Datagramme versendet, sondern einen Datenstrom hat, hilft das PSH-Flag, den Strom effizienter zu verarbeiten, da die empfangende Applikation so gezielter aufgeweckt werden kann und nicht bei jedem eintreffenden Datensegment feststellen muss, dass Teile der Daten noch nicht empfangen wurden, die aber nötig wären, um überhaupt weitermachen zu können.
- Hilfreich ist dies, wenn man zum Beispiel bei einer Telnet -Sitzung einen Befehl an den Empfänger senden will. Würde dieser Befehl erst im Puffer zwischengespeichert werden, so würde dieser (stark) verzögert abgearbeitet werden.
- Das PSH-Flag kann, abhängig von der TCP-Implementation im Verhalten zu obiger Erklärung abweichen.
- RST
- Das Reset-Flag wird verwendet, wenn eine Verbindung abgebrochen werden soll. Dies geschieht zum Beispiel bei technischen Problemen oder zur Abweisung unerwünschter Verbindungen (wie etwa nicht geöffneten Ports, hier wird – anders als bei UDP – kein ICMP-Paket mit „Port Unreachable“ verschickt).
- SYN
- Pakete mit gesetztem SYN-Flag initiieren eine Verbindung. Der Server antwortet normalerweise entweder mit SYN+ACK, wenn er bereit ist, die Verbindung anzunehmen, andernfalls mit RST. Dient der Synchronisation von Sequenznummern beim Verbindungsaufbau (daher die Bezeichnung SYN).
- FIN
- Dieses Schlussflag (finish) dient zur Freigabe der Verbindung und zeigt an, dass keine Daten mehr vom Sender kommen. Die FIN- und SYN-Flags haben Sequenznummern, damit diese in der richtigen Reihenfolge abgearbeitet werden.
- RWin (Receive) Window (2 Byte)
- Ist – nach Multiplikation mit dem RWin#TCP Window Scale Option Fensterskalierungsfaktor – die Anzahl der Daten- Oktett (Informatik) Oktetts (Bytes), beginnend bei dem durch das Acknowledgementfeld indizierten Daten-Oktett, die der Sender dieses TCP-Pakets bereit ist zu empfangen.
- Checksum (2 Byte)
- Die Prüfsumme dient zur Erkennung von Übertragungsfehlern und wird über den TCP-Header, die Daten und einen Pseudo-Header berechnet. Dieser Header besteht aus der Ziel-IP, der Quell-IP, der TCP-Protokollkennung (0x0006) und der Länge des TCP-Headers inkl. Nutzdaten (in Bytes).
- Urgent Pointer (2 Byte)
- Zusammen mit der Sequenz-Nummer gibt dieser Wert die Position des ersten Bytes nach den Urgent-Daten im Datenstrom an. Die Urgent-Daten beginnen sofort nach dem Header. Der Wert ist nur gültig, wenn das URG-Flag gesetzt ist.
- Options (0–40 Byte)
- Das Options-Feld ist unterschiedlich groß und enthält Zusatzinformationen. Die Optionen müssen ein Vielfaches von 32 Bit lang sein. Sind sie das nicht, muss mit Nullbits aufgefüllt werden ( Padding). Dieses Feld ermöglicht, Verbindungsdaten auszuhandeln, die nicht im TCP-Header enthalten sind, wie zum Beispiel die Maximalgröße des Nutzdatenfeldes.
Datenübertragung
TCP-/IP-Segment-Größe
Ein TCP-Segment hat typischerweise eine Größe von maximal 1500 Bytes. Ein TCP-Segment muss jedoch in die darunter liegende Übertragungsschicht passen, das Internetprotokoll (IP); siehe hierzu auch Maximum Transmission Unit (MTU).
IP-Paket e wiederum sind zwar theoretisch bis 65.535 Bytes (64 Kibibyte KiB ) spezifiziert, werden aber selbst meist über Ethernet übertragen, und bei Ethernet ist die Größe der (Layer-3-)Nutzdaten (wenn man von Jumbo Frames absieht) auf 64 (ggf. inklusive Padding) bis 1500 Bytes festgelegt. TCP- und IP-Protokoll definieren jeweils einen Header von 20 Bytes Größe. Für die (Applikations-)Nutzdaten bleiben in einem TCP/IP-Paket also 1460 Bytes (= 1500 Bytes Ethernet-[Nutzdaten] − 20 Bytes Headerdaten TCP − 20 Bytes Headerdaten IP) übrig. Da die meisten Internet-Anschlüsse Digital Subscriber Line DSL verwenden, kommt dort zusätzlich noch das Point-to-Point Protocol Point-to-Point Protocol (PPP) zwischen IP und Ethernet zur Anwendung, was weitere 8 Bytes für den PPP-Rahmen verbraucht. Die Nutzdaten reduzieren sich also auf insgesamt 1500 − 20 − 20 − 8 = 1452 Bytes Maximum Segment Size MSS (Maximum Segment Size). Dies entspricht einer maximalen Nutzdatenrate von 96,8 %.
Aufteilen der Anwendungsdaten auf TCP-/IP-Segmente
Empfänger und Sender einigen sich vor dem Datenaustausch über das Options-Feld auf die Größe der Maximum Segment Size MSS . Die Anwendung, die Daten versenden möchte, etwa ein Webserver, legt zum Beispiel einen 7 Kilobyte großen Datenblock im Puffer ab. Um mit einem 1460 Byte großen Nutzdatenfeld 7 Kilobyte Daten zu versenden, teilt die TCP-Software die Daten auf mehrere Pakete auf, fügt einen TCP-Header hinzu und versendet die TCP-Segmente. Dieser Vorgang wird Segmentierung genannt. Der Datenblock im Puffer wird in fünf Segmente aufgeteilt (siehe Abb. 6). Jedes Segment erhält durch die TCP-Software einen TCP-Header. Die TCP-Segmente werden nacheinander abgeschickt. Diese kommen beim Empfänger nicht notwendigerweise in derselben Reihenfolge an wie sie versendet wurden, da im Internet unter Umständen jedes TCP-Segment einen anderen Weg nimmt. Damit die TCP-Software im Empfänger die Segmente wieder sortieren kann, ist jedes Segment nummeriert. Bei der Zuordnung der Segmente im Empfänger wird die Sequenznummer herangezogen.
Die TCP-Software des Empfängers bestätigt diejenigen TCP-Segmente, die einwandfrei (das heißt mit korrekter Prüfsumme) angekommen sind. Andernfalls werden die Pakete neu angefordert.
Beispiel einer TCP-/IP-Datenübertragung
Der Sender schickt sein erstes TCP-Segment mit einer Sequenznummer SEQ=1 (variiert) und einer Nutzdatenlänge von 1460 Bytes an den Empfänger. Der Empfänger bestätigt es mit einem TCP-Header ohne Daten mit ACK=1461 und fordert damit das zweite TCP-Segment ab dem Byte Nummer 1461 beim Sender an. Dieser schickt es dann mit einem TCP-Segment und SEQ=1461 an den Empfänger. Dieser bestätigt es wieder mit einem ACK=2921 und so weiter. Der Empfänger braucht nicht jedes TCP-Segment zu bestätigen, wenn diese zusammenhängend sind. Empfängt er die TCP-Segmente 1–5, so braucht er nur das letzte TCP-Segment zu bestätigen. Fehlt zum Beispiel das TCP-Segment 3, weil es verlorengegangen ist, so kann er nur die 1 und die 2 bestätigen, 4 und 5 jedoch noch nicht. Da der Sender keine Bestätigung für die 3 bekommt, läuft sein Timer ab, und er verschickt die 3 noch einmal. Kommt die 3 beim Empfänger an, so bestätigt er alle fünf TCP-Segmente, sofern beide Seiten die TCP-Option SACK (Selective ACK) unterstützen. Der Sender startet für jedes TCP-Segment, welches er auf die Reise schickt, einen Retransmission Timer.
Retransmission Timer
Zur Feststellung, wann ein Paket im Netzwerk verloren gegangen ist, wird vom Sender ein Timeout (Netzwerktechnik) Timeout verwendet, bis zu dem das ACK der Gegenseite eingetroffen sein muss. Ein zu niedriger Timeout bewirkt, dass Pakete, die eigentlich korrekt angekommen sind, wiederholt werden; ein zu hoher Timeout bewirkt, dass bei tatsächlichen Verlusten das zu wiederholende Paket unnötig spät gesendet wird. Aufgrund unterschiedlicher Laufzeiten der zugrundeliegenden IP-Pakete ist nur ein dynamisch an die Verbindung angepasster Timer sinnvoll. Die Details werden in RFC 6298 wie folgt festgelegt:
- Der Timeout (RTO = Retransmission Timeout) berechnet sich aus zwei beim Sender mitgeführten Statusvariablen:
- der geschätzten Round Trip Time (SRTT = Smoothed RTT)
- sowie deren Varianz (Stochastik) Varianz (RTTVAR).
- Initial wird geschätzt, dass RTO = 1s (um die Kompatibilität mit der älteren Version des Dokuments zu schaffen sind auch Werte > 1s möglich.)
- Nach der Messung der RTT des ersten gesendeten Pakets wird gesetzt:
- SRTT:= RTT
- RTTVAR:= 0,5 * RTT
- RTO:= RTT + 4 * RTTVAR (Sollte 4 * RTTVAR kleiner sein als die Messgenauigkeit des Timers, wird stattdessen diese addiert.)
- Bei jeder weiteren Messung der RTT' werden die Werte aktualisiert (hierbei muss RTTVAR vor SRTT berechnet werden):
- RTTVAR:= (1-β) * RTTVAR + β * SRTT – RTT' (Auch die Varianz wird mit einem Faktor β geglättet; da die Varianz eine durchschnittliche Abweichung angibt (welche immer positiv ist), wird hier der Betrag der Abweichung von geschätzter und tatsächlicher RTT' verwendet, nicht die einfache Differenz. Es wird empfohlen, β = 1/4 zu wählen.)
- SRTT:= (1-α) * SRTT + α * RTT' (Es wird somit nicht einfach die neue RTT' gesetzt, sondern diese mit einem Faktor α geglättet. Es wird empfohlen, α = 1/8 zu wählen.)
- RTO:= SRTT + 4 * RTTVAR (Sollte 4*RTTVAR kleiner sein als die Messgenauigkeit des Timers, wird stattdessen diese addiert. Für den RTO gilt – unabhängig von der Berechnung – ein Minimalwert von 1 s; es darf auch ein Maximalwert vergeben werden, sofern dieser mindestens 60 s beträgt.)
Durch die Wahl von 2er-Potenzen (4 bzw. 1/2, 1/4 etc.) als Faktoren, können die Berechnungen in der Implementierung durch einfache Bitweiser Operator#Bitweise Verschiebungen Shift-Operationen realisiert werden.
Zur Messung der RTT muss der Karn-Algorithmus von Phil Karn verwendet werden; d. h., es werden nur diejenigen Pakete zur Messung verwendet, deren Bestätigung eintrifft, ohne dass das Paket zwischendurch erneut gesendet wurde. Der Grund dafür ist, dass bei einer erneuten Übertragung nicht klar wäre, welches der wiederholt gesendeten Pakete tatsächlich bestätigt wurde, so dass eine Aussage über die RTT eigentlich nicht möglich ist.
Wurde ein Paket nicht innerhalb des Timeouts bestätigt, so wird der RTO verdoppelt (sofern er noch nicht die optionale obere Schranke erreicht hat). In diesem Fall dürfen (ebenfalls optional) die für SRTT und RTTVAR gefundenen Werte auf ihren Anfangswert zurückgesetzt werden, da sie möglicherweise die Neuberechnung der RTO stören könnten.
Zusammenhang von Flusssteuerung und Staukontrolle
In den folgenden zwei Abschnitten werden die TCP-Konzepte zur Flusssteuerung und Staukontrolle (oder Überlaststeuerung) erläutert. Dabei werden das Sliding Window und das Congestion Window eingeführt. Der Sender wählt als tatsächliche Sendefenstergröße das Minimum aus beiden Fenstern. Um eine zuverlässige Datenübertragung durch Sendewiederholungen zu gewährleisten, werden sogenannte ARQ-Protokoll e (englisch Automatic Repeat reQuest, dt. Automatische Wiederholungsanfrage) eingesetzt.
Flusssteuerung
Da die Anwendung Daten aus dem Puffer liest, ändert sich der Füllstand des Puffers ständig. Deshalb ist es notwendig, den Datenfluss dem Füllstand entsprechend zu steuern. Dies geschieht mit dem Sliding Window und dessen Größe. Den Puffer des Senders erweitern wir, wie in Abb. 8 zu sehen, auf 10 Segmente. In der Abb. 8a werden gerade die Segmente 1–5 übertragen. Die Übertragung ist vergleichbar mit Abb. 7. Obwohl der Puffer des Empfängers in Abb. 7 am Ende voll ist, fordert er mit ACK=7301 die nächsten Daten ab dem Byte 7301 beim Sender an. Dies hat zur Folge, dass das nächste TCP-Segment vom Empfänger nicht mehr verarbeitet werden kann. Ausnahmen sind jedoch TCP-Segmente mit gesetztem URG-Flag. Mit dem RWin Window -Feld kann er dem Sender mitteilen, dass er keine Daten mehr verschicken soll. Dies geschieht, indem er im Window-Feld den Wert Null einträgt (Zero Window). Der Wert Null entspricht dem freien Speicherplatz im Puffer. Die Anwendung des Empfängers liest nun die Segmente 1–5 aus dem Puffer, womit wieder ein Speicherplatz von 7300 Byte frei ist. Damit kann er die restlichen Segmente 6–10 mit einem TCP-Header, der die Werte SEQ=1, ACK=7301 und Window=7300 enthält, beim Sender anfordern. Der Sender weiß nun, dass er maximal fünf TCP-Segmente an den Empfänger schicken kann, und verschiebt das Window um fünf Segmente nach rechts (siehe Abb. 8b). Die Segmente 6–10 werden nun alle zusammen als Burst verschickt. Kommen alle TCP-Segmente beim Empfänger an, so quittiert er sie mit SEQ=1 und ACK=14601 und fordert die nächsten Daten an.
- Silly Window Syndrome
- Der Empfänger sendet ein Zero Window an den Sender, da sein Puffer voll ist. Die Anwendung beim Empfänger liest allerdings nur zwei Byte aus dem Puffer. Der Empfänger schickt einen TCP-Header mit Window=2 (Window Update) an den Sender und fordert gleichzeitig die zwei Byte an. Der Sender kommt der Aufforderung nach und schickt die zwei Byte in einem 42 Byte großen Paket (mit IP-Header und TCP-Header) an den Empfänger. Damit ist der Puffer des Empfängers wieder voll, und er schickt wieder ein Zero Window an den Sender. Die Anwendung liest jetzt zum Beispiel hundert Byte aus dem Puffer. Der Empfänger schickt wieder einen TCP-Header mit einem kleinen Window-Wert an den Sender. Dieses Spiel setzt sich immer wieder fort und verschwendet Bandbreite, da nur sehr kleine Pakete versandt werden. Clarks Lösung ist, dass der Empfänger ein Zero Window sendet und so lange mit dem Window Update warten soll, bis die Anwendung mindestens die maximale Segmentgröße (maximum segment size, in unseren bisherigen Beispielen 1460 Byte) aus dem Puffer gelesen hat oder der Puffer halbleer ist – je nachdem, was zuerst eintritt (Dave Clark, 1982). Auch der Sender kann zu kleine Pakete abschicken und dadurch Bandbreite verschwenden. Dieser Umstand wird mit dem Nagle-Algorithmus beseitigt. Deswegen ergänzt er sich mit Clarks Lösung.
Überlaststeuerung/Staukontrolle (Congestion Control)
Im Internet, in dem viele Netze mit unterschiedlichen Eigenschaften verbunden werden, ist Datenverlust einzelner Pakete durchaus normal. Wird eine Verbindung stark belastet, werden immer mehr Pakete verworfen, die entsprechend wiederholt werden müssen. Durch die Wiederholung steigt wiederum die Belastung, ohne geeignete Maßnahmen kommt es zu einem Datenstau.
Die Verlustrate wird von einem Internet Protocol IP-Netzwerk ständig beobachtet. Abhängig von der Verlustrate wird die Senderate durch geeignete Algorithmus Algorithmen beeinflusst: Normalerweise wird eine TCP/IP-Verbindung langsam gestartet (Slow-Start) und die Senderate schrittweise erhöht, bis es zum Datenverlust kommt. Ein Datenverlust verringert die Senderate, ohne Verlust wird sie wiederum erhöht. Insgesamt nähert sich die Datenrate so zunächst dem jeweiligen zur Verfügung stehenden Maximum und bleibt dann ungefähr dort. Eine Überbelastung wird vermieden.
Algorithmus zur Überlaststeuerung
Gehen bei einer bestimmten Fenstergröße Pakete verloren, kann das festgestellt werden, wenn der Sender innerhalb einer bestimmten Zeit ( Timeout (Netzwerktechnik) Timeout ) keine Bestätigung (ACK) erhält. Man muss davon ausgehen, dass das Paket aufgrund zu hoher Netzlast von einem Router im Netz verworfen wurde. Das heißt, der Puffer eines Routers ist vollgelaufen; es handelt sich hier sozusagen um einen Stau im Netz. Um den Stau aufzulösen, müssen alle beteiligten Sender ihre Netzlast reduzieren. Dazu werden im RFC 2581 vier Algorithmen definiert: slow start, congestion avoidance, fast retransmit und fast recovery, wobei slow start und congestion avoidance zusammen verwendet werden. Die zwei Algorithmen fast retransmit und fast recovery werden auch zusammen verwendet und sind eine Erweiterung der Algorithmen slow start und congestion avoidance.
Slow Start Slow Start und Congestion Avoidance
Zu Beginn einer Datenübertragung dient der Slow-Start-Algorithmus zur Bestimmung des congestion window (wörtlich: Überlastfenster), um einer möglichen Überlastsituation vorzubeugen. Man möchte Staus vermeiden, und da die momentane Auslastung des Netzes nicht bekannt ist, wird mit zunächst kleinen Datenmengen begonnen. Der Algorithmus startet mit einem kleinen Fenster von einer Maximum Segment Size MSS (Maximum Segment Size), in dem Datenpakete vom Sender zum Empfänger übertragen werden.
Der Empfänger sendet nun eine Bestätigung (ACK) an den Sender zurück. Für jedes empfangene ACK wird die Größe des congestion window um eine MSS erhöht. Da für jedes versandte Paket bei erfolgreicher Übertragung ein ACK geschickt wird, führt dies innerhalb einer Roundtrip-Zeit zu einer Verdopplung des Congestion Windows. In dieser Phase gibt es also ein exponentielles Wachstum. Wenn das Fenster beispielsweise das Versenden von zwei Paketen gestattet, so erhält der Sender auch zwei ACKs und erhöht das Fenster daher um 2 auf 4. Dieses exponentielle Wachstum wird so lange fortgesetzt, bis der sogenannte Slow-Start Threshold erreicht wird (engl. threshold ‚Schwelle‘). Die Phase des exponentiellen Wachstums wird auch Slow Start Phase genannt.
Danach wird das Congestion Window nur noch um eine MSS erhöht, wenn alle Pakete aus dem Fenster erfolgreich übertragen wurden. Es wächst also pro Roundtrip-Zeit nur noch um eine MSS, also nur noch linear. Diese Phase wird als Congestion Avoidance Phase bezeichnet. Das Wachstum wird beendet, wenn das vom Empfänger festgelegte Empfangsfenster erreicht worden ist (siehe Fluss-Steuerung).
Kommt es zu einem Timeout, wird das congestion window wieder auf 1 zurückgesetzt, und der slow-start threshold wird auf die Hälfte der Flight Size (Flight Size ist die Anzahl an Paketen, die verschickt, aber noch nicht quittiert wurden) herabgesetzt. Die Phase des exponentiellen Wachstums wird also verkürzt, so dass das Fenster bei häufigen Paketverlusten nur langsam wächst.
Fast-Retransmit und Fast-Recovery
Fast-Retransmit und Fast-Recovery („schnelles Erholen“) werden eingesetzt, um nach einem Paketverlust schneller auf die Stau-Situation zu reagieren. Dazu informiert ein Empfänger den Sender, wenn Pakete außer der Reihe ankommen und somit dazwischen ein Paketverlust vorliegt. Hierfür bestätigt der Empfänger das letzte korrekte Paket erneut für jedes weitere ankommende Paket außer der Reihe. Man spricht dabei von Dup-Acks ( duplicate acknowledgments), also mehrere aufeinanderfolgende Nachrichten, welche dasselbe Datensegment ACKen. Der Sender bemerkt die duplizierten Bestätigungen, und nach dem dritten Duplikat sendet er sofort, vor Ablauf des Timers, das verlorene Paket erneut. Weil nicht auf den Ablauf des Timers gewartet werden muss, heißt das Prinzip Fast Retransmit. Die Dup-Acks sind auch Hinweise darauf, dass zwar ein Paketverlust stattfand, aber doch die folgenden Pakete angekommen sind. Deshalb wird das Sendefenster nach dem Fehler nur halbiert und nicht wie beim Timeout wieder mit Slow-Start begonnen. Zusätzlich kann das Sendefenster noch um die Anzahl der Dup-Acks erhöht werden, denn jedes steht für ein weiteres Paket, welches den Empfänger erreicht hat, wenn auch außer der Reihe. Da dadurch nach dem Fehler schneller wieder die volle Sendeleistung erreicht wird, nennt man das Prinzip Fast-Recovery.