TCP/UDP - Informatik 4 - RWTH

Werbung
Rheinisch-Westfälische Technische Hochschule Aachen
Lehrstuhl für Informatik IV
Prof. Dr. rer. nat. Otto Spaniol
TCP / UDP
Proseminar: Kommunikationsprotokolle
SS 2003
Stefan Hoferer
Matrikelnummer: 234173
Betreuung:
Ralf Wienzek
Lehrstuhl für Informatik IV, RWTH Aachen
Inhaltsverzeichnis
1 Einleitung
3
2 Grundlagen von TCP/IP
3
2.1
Der Protokollstapel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2.2
Ports und Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
3 UDP
5
3.1
Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
3.2
Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
3.3
Fragmentierung durch IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
3.4
Effekte zwischen UDP und ARP . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
3.5
Anwendungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
4 TCP
9
4.1
Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
4.2
Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
4.2.1
Header Optionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
Verbindungsmanagement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
4.3.1
Verbindungsaufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
4.3.2
Verbindungsabbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
4.3.3
Zustandsübergangsdiagramm . . . . . . . . . . . . . . . . . . . . . . . . .
17
Datenübertragung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
4.4.1
Verbindungssicherheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
4.4.2
Interaktiver Datentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
4.4.3
Bulk-Datentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
4.3
4.4
5 Zusammenfassung
24
2
1 Einleitung
Beide der hier behandelten Protokolle gehören zum TCP/IP-Protokollstapel, über den seit 1983 ein
Großteil der Kommunikationsaufgaben im Internet abgewickelt wird. Aber auch schon vor TCP/IP
gab es das Bedürfnis Daten zwischen Computern auszutauschen. Bereits 1969 rief die Defence Advanced Research Projects Agency (DARPA) ein Projekt ins Leben, aus dem das so genannte ARPANET entstand. Die Zielsetzung dabei war ein heterogenes Netzwerk zu schaffen, das weitestgehend
unabhängig von dem verwendeten Übertragungsmedium oder den daran angeschlossenen Rechnersystemen war. Außerdem sollte es eine einheitliche Schnittstelle zu diesen Protokollen geben, um die
Entwicklung von Software deutlich zu vereinfachen. Nachdem das ARPANET in Betrieb genommen
wurde und sich stark verbreitete, begann die Entwicklung der TCP/IP-Protokolle, die seit 1983 die
Grundlage unseres heutigen Internets bilden. Wegen seiner großen Bedeutung ist TCP/IP heute für
alle gängigen Rechnersysteme verfügbar. Bei den meisten ist es sogar direkt in das Betriebssystem
integriert.
Zwei der Protokolle des o.g. Protokollstapels sollen hier behandelt werden. Das verbindungsorientierte Transmission Control Protocol (TCP) [2], das aufgrund seiner großen Bedeutung mit zur Namensgebung von TCP/IP beitrug, sowie das verbindungslose User Datagram Protocol [1].
Im Folgenden werden zunächst einige Grundlagen, die den TCP/IP-Protokollstapel betreffen, erläutert.
Wobei schon hier erwähnt sei, dass es sich dabei nur um einen groben Überblick handelt. Für detailliertere Informationen sei auf die Seminararbeiten zum Thema “Was ist das Internet? Struktur, Aufbau
und Technik”, “Routing im Internet”, “Was ist Ethernet?” sowie “IPv4 und IPv6” verwiesen. Nach
der Behandlung der Grundlagen werden die beiden Protokolle UDP und TCP ausführlich behandelt.
2 Grundlagen von TCP/IP
2.1 Der Protokollstapel
Kommunikationsprotokolle werden, um ihre Komplexität zu verringern, schichtweise implementiert.
Auch wenn Anzahl und Aufgabenverteilung der Schichten von Netz zu Netz variiert, ist das grundsätzliche Prinzip, stets das gleiche. Eine Schicht bietet der jeweils über ihr liegenden Schicht bestimmte Dienste an, ohne jedoch Kenntnisse über die genaue Implementierung vorauszusetzen. In jeder
Schicht können mehrere Dienste vorhanden sein, welche die Aufgaben der Schicht auf verschiedene
Weise implementieren. Auf diese Weise kann die Implementierung einzelner Dienste geändert werden, ohne damit die restlichen zu beeinflussen. Wichtiger ist noch, dass man auf diese Weise neue
Hardware (zum Beispiel für die Kommunikation über andere Netzwerkmedien) auf einfache Weise
integrieren kann.
Eine Anwendung auf Rechner A, die Daten an eine Anwendung auf Rechner B schicken möchte,
kann dies nicht auf direktem Weg. Stattdessen gibt sie die Daten an einen Dienst der obersten Schicht
weiter, welcher seine Steuerinformationen in Form von so genannten Headern hinzufügt und seinerseits Dienste der darunterliegenden Schicht nutzt, um die Daten weiterzugeben. Erst auf der untersten
3
ISO / OSI
TCP / IP
Verarbeitungsschicht
Verarbeitungsschicht
Im Modell
nicht
vorhanden
Darstellungsschicht
Sitzungsschicht
Transportschicht
Transportschicht
Vermittlungsschicht
Internetschicht
Sicherungsschicht
Host-an-Netz Schicht
Bitübertragungsschicht
Abbildung 1: ISO/OSI- und TCP/IP-Protokollstapel im Vergleich
Ebene werden die Daten von Rechner A zu Rechner B transportiert und durchlaufen dort den Protokollstapel von unten nach oben. Dabei werden die Steuerinformationen in den Headern u.a. dazu
genutzt, um das Protokoll und letztlich die Anwendung zu bestimmen, an welche die Daten weitergegeben werden sollen.
Die zwei wichtigsten Modelle für die Aufgabenverteilung der Schichten sind das ISO/OSI-Referenzmodell sowie das TCP/IP-Referenzmodell (s. Abb. 1). Im Gegensatz zu den 7 Schichten des ISO/OSIModells werden bei TCP/IP nur 4 Schichten implementiert. Es hat sich aber gezeigt, dass dies völlig
ausreichend ist.
Da in dieser Arbeit Protokolle aus dem TCP/IP-Protokollstapel vorgestellt werden, sollen im Folgenden lediglich die Aufgaben dieser vier Schichten beschrieben werden.
• Host-an-Netz-Schicht
Diese Schicht übernimmt die Aufgaben der Sicherung und der Bitübertragung. Die Protokolle
dieser Schicht sind von Netz zu Netz sehr unterschiedlich und von TCP/IP nicht weiter festgelegt. Die einzige Anforderung, die an sie gestellt wird, ist, dass IP-Pakete verschickt werden
können.
• Internet-Schicht
In dieser Schicht ist das wohl wichtigste Protokoll angesiedelt, das Internet Protocol (IP). Es
soll sicherstellen, dass IP-Pakete richtig zugestellt werden können. IP übernimmt dabei Aufgaben wie die Adressierung der Daten und das so genannte Routing zwischen verschieden
Netzwerken. Das Internet Protocol ist verbindungslos und übernimmt keine Garantie, dass die
versendeten Daten an ihrem Ziel ankommen. Die Erkennung verloren gegangener Pakete und
eine geeignete Reaktion darauf wird höheren Schichten überlassen.
4
• Transportschicht
Hier sind die beiden Ende-zu-Ende Protokolle TCP und UDP definiert. UDP ist genau wie IP
ein verbindungsloses und unzuverlässiges Protokoll, während TCP ein zuverlässiges verbindungsorientiertes Protokoll darstellt. Anwendungen, die Daten verschicken möchten, haben die
Wahl, welches der Protokolle sie verwenden möchten. Beide haben ihre Vor- und Nachteile, auf
die in den entsprechenden Abschnitten näher eingegangen wird.
• Verarbeitungsschicht
In dieser Schicht sind höhere Protokolle angesiedelt. Zu diesen gehören zum Beispiel TELNET,
FTP, SMTP oder DNS, die zur Datenübertragung die Dienste von UDP oder TCP nutzen.
2.2 Ports und Sockets
Um im Netzwerk den Rechner ausfindig zu machen, an den die Daten geschickt werden sollen, werden IP-Adressen verwendet. Sind die Daten an ihrem Zielrechner angekommen muss es auch eine
Möglichkeit geben, sie einem bestimmten Programm bzw. Prozess zuzuordnen. Diese Zuordnung erfolgt sowohl bei TCP als auch bei UDP über so genannte Ports. Ports sind 16 Bit groß, haben also
einen Wertebereich von 0 bis 65.535. Ports im Bereich von 0 bis 1023 werden als well-known Ports
bezeichnet. Hinter diesen Nummern verbergen sich standardmäßig bestimmte Programme oder Prozesse, so dass zum Beispiel ein Benutzer, der sich mittels SSH zu einem entfernten Rechner verbinden
möchte, weiß, dass er dies über Port 22 machen kann. Um entscheiden zu können, an welchen Prozess
die Daten ausgeliefert werden sollen, kann jede Portnummer nur genau einmal zugewiesen werden.
Allerdings kann ein Port für UDP und TCP gleichzeitig vergeben werden. Denn im empfangenden
Rechner kann anhand der im IP-Header untergebrachten Steuerinformationen entschieden werden, an
welchen der beiden Dienste die Daten weitergegeben werden und somit ist die Zuweisung eindeutig.
Die Kombination aus IP-Adresse und Port bezeichnet man als Socket.
3 UDP
3.1 Einführung
Wie breits erwähnt lässt sich das User Datagram Protocol [1] als verbindungslos und unzuverlässig
charakterisieren. Das bedeutet, dass Daten ohne vorherige Ankündigung oder Überprüfung auf Erreichbarkeit des Hosts abgeschickt werden und dass bei Übertragungsfehlern die betroffenen Datensätze nicht erneut übertragen werden. In beiden Punkten unterscheidet sich UDP von TCP. Ein
weiterer Unterschied besteht in der Art, wie die Daten verschickt werden. Die UDP-Schicht verschickt die Daten als Datagramme in der von der Anwendung bestimmten Größe, während die TCPSchicht die Größe der Datensätze selbstständig bestimmt. Da das zugrunde liegende Netzwerk aber
5
16-Bit Source Port Number
16-Bit Destination Port Number
16-Bit UDP Length
16-Bit UDP Checksum
8 Byte
Daten (Sofern vorhanden)
Abbildung 2: UDP-Header
nur eine begrenzte Kapazität hat, kann es die Daten möglicherweise nicht zusammenhängend transportieren. Sie müssen also unterteilt (fragmentiert) werden. Diese Fragmentierung wird durch die
IP-Schicht vorgenommen und führt zu einem größeren Datenaufkommen, da für jedes Segment ein
neuer Header generiert werden muss, damit alle Fragmente ihr Ziel finden. Durch diese Fragmentierung vergrößert sich aber auch die Übertragungsunsicherheit, denn die Gegenseite kann mit einzelnen
Fragmenten nichts anfangen. Erst wenn alle Fragmente durch die IP-Schicht wieder in der richtigen
Reihenfolge zusammengesetzt wurden, kann der Prozess die Daten auswerten. Aufgrund eines begrenzten Empfangspuffers können Fragmente nicht unbegrenzt zwischengespeichert werden. Nach
einem festgelegten Zeitraum werden diese Daten verworfen. Auf die Fragmentierung durch IP wird
in Abschnitt 3.3 eingegangen.
Trotz dieser Schwierigkeiten hat UDP seine Daseinsberechtigung. Anwendungen die UDP verwenden
werden in Abschnitt 3.5 beschreiben.
3.2 Header
Der UDP-Header belegt 8 Byte, die in 4 je 2 Byte große Felder aufgeteilt sind (s. Abb. 2). Der an den
Header angehängte Datenblock hat keine festgelegte Größe.
• Source Port (Bit 0 - 15)
Für den Fall, dass die Gegenseite antworten möchte, kann sie Pakete an den hier angegebenen
Port senden. Der sendende Rechner muss aber nicht zwangsläufig auf dem hier angegebenen
Port empfangsbereit sein.
• Destination Port (Bit 16 - 31)
Dieses Feld enthält den Port, auf dem ein Prozess auf dem Zielrechner auf UDP-Datagramme
wartet. In vielen Fällen handelt es sich hier um die schon angesprochenen well-known Ports.
• UDP Length (Bit 32 - 47)
Hier wird die Länge des gesamten Datagramms, also sowohl die der Nutzdaten als auch des
Headers, in Byte angegeben. Da das Lenght-Feld im IP-Header ebenfalls 2 Bytes groß ist, kann
6
32-Bit Source IP Address
32-Bit Destination IP Address
Zero
8-Bit Protocol (17)
UDP
Pseudo
Header
16-Bit UDP Length
16-Bit Source Port Number
16-Bit Destination Port Number
16-Bit UDP Length
16-Bit UDP Checksum
UDP
Header
Daten (Sofern vorhanden)
Pad Byte (0)
Abbildung 3: Pseudo Header zur Checksum-Berechnung
die maximale Datenmenge eines UDP-Pakets nicht größer als 65.535 Byte (16 Bit unsigned) 20 Byte des IP-Headers - 8 Byte des UDP-Headers = 65.507 Byte sein.
• Checksum (Bit 48 - 63)
Die Prüfsumme (Checksum) erlaubt es, Fehler in der Datenübertragung aufzudecken. Ein solcher Fehler führt dazu, dass ein Datagramm ohne Fehlermeldung gelöscht wird. Die Berechnung der Prüfsumme deckt das komplette UDP-Datagramm, also sowohl den Header als auch
die Daten, ab. Zusätzlich wird ein Pseudo-Header, der einige Felder des IP-Headers enthält, zur
Berechnung hinzugezogen (s. Abb. 3). Bei der Berechnung werden 16-Bit-Wörter im EinerKomplement addiert und das Einer-Komplement dieser Summe im Checksum-Feld eingetragen. Eine ungerade Bytezahl im Datenteil wird durch ein Pad-Byte mit Wert 0 ausgeglichen,
das aber nicht mit übertragen wird.
Im Gegensatz zu TCP ist bei UDP die Berechnung der Prüfsumme zwar nicht vorgeschrieben,
wird aber immer empfohlen. Wenn keine Berechnung erfolgt, wird die Prüfsumme 0 gespeichert. Ergibt eine Berechnung den Wert 0, wird dieser, wie im Einer-Komplement üblich, durch
16 1-Bits repräsentiert.
3.3 Fragmentierung durch IP
Eine Anwendung, die ihre Daten über UDP verschickt, legt die Größe der Datagramme fest, das
bedeutet, dass jeder Schreibvorgang einer Anwendung zu einem eigenen Datagramm führt. Da die
Größe der auf einmal übertragbaren Daten eines Netzwerkes durch die Maximum Transfer Unit
7
(MTU) nach oben begrenzt ist, sollten Anwendungen darauf bedacht sein, die Datagramme nicht
zu groß werden zu lassen. Anderenfalls müssen diese fragmentiert werden, was für jedes Fragment
einen Overhead von 20 Byte bedeutet.
Der IP-Schicht ist nur die MTU des Netzes, an das der Rechner direkt angeschlossen ist bekannt.
Ein Paket muss aber unter Umständen viele unterschiedliche Netze mit verschieden großen MTUs
durchlaufen, bevor es den Zielhost erreicht. Ist die MTU eines dieser Netze kleiner als die Größe des
Datensatzes, muss dieser Datensatz durch den entsprechenden Router fragmentiert werden, bevor er
weitergeschickt werden kann. Unter Umständen muss in folgenden Netzen der schon fragmentierte Datensatz erneut fragmentiert werden. Wird beim Versand eines Datensatzes das IP-Header-Flag
Don’t Fragment gesetzt, um eine Fragmentierung zu verhindern, werden alle Pakete die größer als
die Path-MTU sind verworfen. Als Path-MTU wird die kleinste MTU auf dem Pfad zwischen zwei
Rechnern bezeichnet.
3.4 Effekte zwischen UDP und ARP
Das Address Resolution Protocol (ARP) [3] wird verwendet, um zu einer IP-Adresse die zugehörige
Hardwareadresse zu bestimmen. Wenn der ARP-Cache leer und das zu sendende UDP-Datagramm
groß ist, kann ein interessanter Effekt zwischen diesen beiden Protokollen beobachtet werden. Das
große UDP-Datagramm impliziert, dass es schon für den Versand durch das erste Netz fragmentiert
werden muss. Die IP-Schicht generiert die Fragmente viel schneller, als eine Antwort auf die ARPAnfrage für das erste Paket eintrifft. Also werden für alle weiteren Fragmente ebenfalls wegen des
noch leeren Caches ARP-Anfragen generiert, was zum so genannten ARP-Flooding führt. Typische
ARP-Implementierungen verwenden einen Puffer, in welchem Pakete zwischengespeichert werden,
für die ein ARP-Request verschickt werden muss. Pakete in diesem Puffer werden überschrieben,
sobald ein neues Paket verschickt werden soll. Nachdem die Antwort auf die erste Anfrage ankommt,
wird nur noch das letzte Paket verschickt, da jedes Paket durch seinen Nachfolger im Puffer überschrieben wurde, und sich nur noch das letzte Paket darin befindet. Über diesen Fehler wird der
Sender nicht informiert. Auch der Empfänger kann keine Fehlermeldung generieren, da der UDPHeader, der sich im ersten Paket befand, nie angekommen ist. Es kann also nicht mehr zugeordnet
werden, von welchem Prozess dieses Paket stammte. Nach einem Timeout muss der Empfänger dieses
einzelne Paket verwerfen.
3.5 Anwendungen
Gerade wegen seiner Einfachheit gibt es einige Anwendungen, die UDP als Transportprotokoll bevorzugen. Vor allem bei geringen Datenmengen bedeutet der kleine Header einen im Vergleich zu den
Nutzdaten geringen Overhead. Auch die Tatsache, dass keine Verbindung aufgebaut werden muss,
reduziert im Vergleich zu TCP den Overhead.
Ein Anwendungsgebiet ist der Client-Server Bereich, wo der Datenaustausch in Form von Anfrage und Antwort abläuft. Der Host, der die Anfrage verschickt, wird im Allgemeinen als Client, der
Empfänger der Anfrage als Server bezeichnet. Gehen Daten bei der Übertragung in eine der beiden
8
Richtungen verloren, startet die Anwendung, nachdem sie bei Ablauf eines Timers keine Antwort erhalten hat, eine erneute Anfrage. Als Beispiel für eine solche Anwendung ist Remote-Procedure-Call
(RPC) [5] zu erwähnen. RPC ermöglicht es, Funktionen auf entfernten Rechnern aufzurufen, wobei der Funktionsaufruf sich bis auf wenige Einschränkungen nicht von “normalen” lokalen Funktionsaufrufen unterscheidet. Diese Vorgehensweise erleichtert deutlich die Programmierung von Netzwerkanwendungen.
Ein weiteres wichtiges Anwendungsgebiet sind alle Arten von multimedialen Datenübertragungen
wie digitales Fernsehen, Internet Radio oder Videokonferenzen, also Anwendungen bei denen es
wichtig ist, dass sie in Echtzeit empfangen werden. Hier ist es von Vorteil, das UDP über keine
Art von Empfangsbestätigung oder erneutem Datagrammversand verfügt. Übertragungsfehler führen
dann zu kurzen Übertragungslücken, die weiteren Daten kommen aber nach wie vor in Echtzeit an.
Bei TCP als Transportprotokoll käme es aufgrund der erneuten Segmentübertragung zu Verzögerungen der folgenden Daten. So könnte also keine Echtzeit gewährleistet werden.
Für diesen Anwendungsbereich wurde 1989 das heute weit verbreitete Real-Time Transport Protocol (RTP) [6] entwickelt. Es ist der Anwendungsschicht zugeordnet, obwohl es von der Arbeitsweise
eigentlich der Transportschicht zugeordnet werden müsste. Dieses Protokoll ermöglicht durch einen
weiteren Header einige Funktionen, die für multimediale Anwendungen nützlich sind. Beispielsweise werden die Datagramme nummeriert, um im Falle eines Datenverlustes entsprechend reagieren
zu können. Fehlen nur wenige Daten kann so versucht werden, diese zu interpolieren. Eine weitere
Funktion von RTP ist der Timestamp. Er ermöglicht eine relative Zeitangabe der Daten zum ersten
übertragenen Datagramm. So können Daten zwischengespeichert werden, um dann zum richtigen
Zeitpunkt ausgewertet zu werden.
4 TCP
4.1 Einführung
Wie bereits erwähnt, handelt es sich bei TCP [2] um ein zuverlässiges, verbindungsorientiertes Protokoll, das Daten als Bytestrom versendet. Verbindungsorientiert bedeutet, dass bevor Daten ausgetauscht werden können, eine Verbindung zwischen den beiden Rechnern hergestellt werden muss. Bei
diesem Verbindungsaufbau werden wichtige Daten ausgetauscht, um die Verbindung zu initialisieren.
Diese TCP-Verbindungen arbeiten im Fullduplex-Betrieb, das heißt beide Seiten können unabhängig
voneinander Daten verschicken.
TCP und UDP unterscheiden sich in der Art der Datenübertragung. Aus diesem Grund werden die
Datensätze auch mit unterschiedlichen Namen versehen. Während man bei UDP von einem Datagramm spricht, ist bei TCP von einem Segment die Rede. Im Gegensatz zu UDP, wo die Anwendung
die Paketgröße und Anzahl festlegt, hat eine Anwendung, die Daten über TCP verschickt, keinen Einfluss auf die Größe der Segmente. Dabei ist es durchaus denkbar, dass beispielsweise 5 Segmente à
20 Byte versendet werden und diese auf der Gegenseite als 100 Byte oder 10 mal 10 Byte von der Anwendung gelesen werden. Außerdem überwacht die TCP-Schicht, wiederum im Gegensatz zu UDP,
anhand der Sequenznummer die Reihenfolge, in der die Daten beim Empfänger eintreffen.
9
16-Bit Source Port Number
16-Bit Destination Port Number
32-Bit Sequence Number
32-Bit Acknowledgment Number
U A P R S F
4-Bit
6-Bit Reserverd R C S S Y I
Header
G K H T N N
16-Bit Window Size
16-Bit TCP Checksum
16-Bit Urgent Pointer
20 Byte
Options (Sofern vorhanden)
Daten (Sofern vorhanden)
Abbildung 4: TCP-Header
Um Zuverlässigkeit gewährleisten zu können, gibt es verschiedene Ansatzpunkte. Jedem versendeten Byte wird eine Sequenznummer (Sequence Number) zugeordnet, wobei in dem entsprechenden
Header-Feld jeweils die Sequenznummer des ersten Bytes eines Segmentes gespeichert wird. Nach
dem erfolgreichen Empfang eines Segmentes auf der Gegenseite versendet diese eine Empfangsbestätigung. Bleibt eine Bestätigung aus, werden die Bytes ab dem letzten bestätigten Byte erneut
übertragen.
Außerdem verfügt TCP wie auch UDP über ein Header-Feld Checksum. Diese Prüfsumme wird nach
dem gleichen Prinzip berechnet, muss aber im Gegensatz zu UDP immer berechnet und überprüft
werden. Bei fehlerhafter Prüfsumme wird das Segment gelöscht, da in dem Fall einer ausbleibenden
Bestätigung der Sender die Daten erneut überträgt.
Als erstes folgt nun eine Beschreibung aller Felder des TCP-Headers. Im Anschluss wird ausführlich
auf die Punkte Verbindungsaufbau, Verbindungsabbau und Datentransfer eingegangen.
4.2 Header
Da TCP, wie auch UDP, das unzuverlässige, verbindungslose Internet Protocol zum Versenden der
Daten verwendet, werden einige zusätzliche Informationen benötigt, um den gewünschten Dienst
anbieten zu können. Hierzu wird ein Header mit einer Mindestgröße von 20 Byte, also 12 Byte mehr
als bei UDP, verwendet (s. Abb. 4). Der Datenteil ist bei TCP optional. Das heißt, es können auch
Segmente verschickt werden, die nur aus einem Header bestehen.
Die Bedeutung der einzelnen Felder wird im Folgenden beschrieben.
10
• Source Port (Bit 0 - 15), Destination Port (Bit 16 - 31)
Eine Verbindung wird eindeutig über das 4-Tupel (Source-IP, Source-Port, Destination-IP, Destination-Port) identifiziert. Da die IP-Adresse der beiden Hosts im IP-Header festgelegt wird,
müssen im TCP-Header nur die Ports gespeichert werden. Über diese Ports kann entschieden
werden, an welche Anwendung auf dem jeweiligen Host die Daten weitergegeben werden sollen.
• Sequence Number (Bit 32 - 63)
Jedem Byte wird eine Sequenznummer zugeordnet, wobei die Nummer des ersten versendeten
Bytes jeder Seite während des Verbindungsaufbaus festgelegt wird. Diese Nummer wird vorzeichenlos gespeichert, daher können Nummern von 0 bis 232 − 1 vergeben werden, bevor es
zu einem Überlauf kommt.
• Acknowledgment (Bit 64 - 95)
Die Bestätigungsnummer (Acknowledgment) gibt die Sequenznummer an, die als nächste erwartet wird. Sie ist nur gültig, wenn das ACK-Flag gesetzt ist. Implizit wird der Empfang aller
Bytes mit kleinerer Sequenznummer bestätigt.
• Header Length (Bit 96 - 99)
Die Länge des TCP-Headers kann aufgrund des Option-Feldes zwischen 20 Byte (keine Optionen) und 60 Byte variieren. Da mit den zur Verfügung stehenden 4 Byte nur 16 Werte dargestellt
werden können, wird hier die Header-Länge in 32-Bit Worten angegeben.
• Reserved (Bit 100 - 105)
Dieser Bereich wird bis heute nicht genutzt. Die Tatsache, dass dieses Feld über ein Jahrzehnt
“überlebt” hat, wird als Beleg dafür angesehen, wie gut TCP ausgelegt wurde.
• 6 Flags (Bit 106 - 111)
– URG Urgent
Dringende Daten wurden versendet. Der Urgent Pointer wurde gesetzt.
– ACK Acknowledgment
Durch das Ack-Bit wird angezeigt, dass die Bestätigungsnummer gesetzt ist, um den Empfang von Daten zu mitzuteilen.
– PSH Push
Wenn dieses Bit gesetzt ist, werden Daten so schnell wie möglich an die Anwendung
weitergegeben.
– RST Reset
Setzt eine Verbindung zurück.
– SYN Synchronize
Dieses Flag wird gesetzt, wenn eine neue Verbindung aufgebaut wird. (s.u.)
– FIN Finished
FIN dient zum Beenden einer Verbindung.
11
• Window Size (Bit 112 - 127)
Der TCP-Empfangs-Puffer hat nur eine begrenzte Größe. Aus diesem Grund wird in diesem
Feld angegeben, wie viele Byte noch empfangen werden können. Dadurch wird erreicht, dass
kein schneller Sender einen langsamen Empfänger mit Daten überfluten kann.
• Checksum (Bit 128 - 143)
Die Berechnung die gleiche wie bei UDP. Der einzige Unterschied ist, dass die Berechnung und
Auswertung hier obligatorisch ist und nicht wie bei UDP lediglich empfohlen wird.
• Urgent Pointer (Bit 144 - 159)
Bei gesetztem URG-Bit wird durch diesen Pointer das letzte Byte dringender Daten gekennzeichnet. Diese Daten werden dann umgehend, ohne Beachtung der Reihenfolge des Datenstroms, an den Prozess weitergeleitet.
• Options (zwischen 0 und 40 Byte)
Dieses Feld ermöglicht die Verwendung von Funktionen, die im normalen Header nicht verfügbar
sind. Im nächsten Abschnitt werden dazu einige Beispiele angegeben.
4.2.1 Header Optionen
Soll dieses Feld für eine zusätzliche Option verwendet werden, muss zuerst der Typ, dann die Länge
der Option und zum Schluss die eigentliche Option angegeben werden. Ist die Option lediglich ein
Flag braucht nur der Typ angegeben werden. Die Gesamtlänge der Optionen muss ein Vielfaches von
4 Byte betragen, da die Header-Länge ein Vielfaches von 32-Bit (4 Byte) betragen muss.
End Of Option List (Typ 0) Mit dieser Option wird das Ende der Optionenliste im Header markiert.
No Operation (Typ 1) Diese Option dient zum Auffüllen des Headers auf ein Vielfaches von 4 Byte.
Maximum Segment Size (Typ 2) Diese Option wird häufig beim Verbindungsaufbau verwendet und
in diesem Zusammenhang noch genauer erläutert. Die Länge der Option ist auf 4 Byte festgelegt.
4.3 Verbindungsmanagement
4.3.1 Verbindungsaufbau
Vor jedem Datentransfer muss zuerst eine Verbindung hergestellt werden. In den meisten Fällen werden Verbindungen zwischen einem Server, der einen speziellen Dienst anbietet, und einem Client,
der diesen Nutzen will, hergestellt. Wobei der Wunsch nach einer Verbindung dann meist aktiv vom
Client ausgeht. Es gibt aber auch Fälle, in denen beide Parteien nahezu gleichzeitig eine Verbindung
aufbauen wollen. Beide Varianten werden im Folgenden beschrieben.
12
Mit dem Aufbau einer Verbindung werden zwei Dinge beabsichtigt: Zum einen kann so überprüft
werden, ob der Rechner, mit dem Daten ausgetauscht werden sollen, überhaupt empfangsbereit ist,
zum anderen werden so wichtige, für die Verbindung benötigte Daten ausgetauscht.
Eine erste wichtige Information, die dabei ausgetauscht wird, ist die Initial Sequence Number (ISN).
ISN + 1 ist die Nummer des ersten zu versendenden Byte, da das SYN-Flag seinerseits eine Sequenznummer “verbraucht”. Bei jedem Verbindungsaufbau sollte die ISN variieren. Hierdurch soll
verhindert werden, dass Segmente, die verspätet ankommen, nicht versehentlich der aktuellen Verbindung zugeordnet werden können. RFC 793 [2] schreibt dabei vor, die ISN als 32 Bit-Zähler alle
4 Mikrosekunden zu erhöhen. Tatsächlich wird die ISN in verschiedenen Implementierungen auf
unterschiedliche Weise generiert (4.4BSD erhöht den Wert des Zählers beispielsweise alle 8 Mikrosekunden).
Nach einem Verbindungsaufbau ist beiden Seiten der Socket ihres Kommunikationspartners bekannt.
Über dieses 4-Tupel (RechnerA IP-Adresse, RechnerA Port, RechnerB IP-Adresse, RechnerB Port)
ist eine TCP-Verbindung eindeutig identifiziert. Mehrere Verbindungen zwischen zwei Rechnern sind
problemlos möglich, wenn für neue Verbindungen auf mindestens einem Rechner ein anderer Port
verwendet wird.
Oft wird beim Verbindungsaufbau auch die Maximum Segment Size (MSS) ausgetauscht. Die MSS
ist ein Beispiel für eine Funktion, die vom Standard-Header nicht zur Verfügung gestellt wird und
aus diesem Grund über das Feld Options realisiert wird. Sie ist 4 Byte groß und gibt die Segmentgröße, die maximal empfangen werden kann, in 2 Byte an. Geben beide Rechner eine MSS an, ist die
niedrigere Zahl ausschlaggebend. Wird dagegen keine MSS angegeben, werden maximal 536 Byte
an Daten versendet. Das entspricht einem IP-Paket von 536 Byte (Daten) + 20 Byte (TCP-Header) +
20 Byte (IP-Header) = 576 Byte.
3-Way-Handshake (3 Wege Handschlag)
Ein Großteil aller Verbindungen wird über den so genannten 3-Way-Handshake aufgebaut. Wie der
Name vermuten lässt, werden hier 3 Segmente ausgetauscht, um die Verbindung zu initialisieren.
Abbildung 5 zeigt einen solchen typischen Verlauf. Vorraussetzung ist hierbei immer, dass auf einem
Rechner (meist als Server bezeichnet) ein Prozess (z.B. SSH, FTP, etc.) gestartet ist, der auf einem
festgelegten Port auf Verbindungen von anderen Rechnern wartet. Der Zustand von diesem Server
wird mit LISTEN bezeichnet.
Angaben des Zustandes wie hier LISTEN beziehen sich auf Abbildung 7, in der eine Übersicht über
alle möglichen Zustände gegeben ist.
1. Das erste Segment geht vom Client aus, der einen Dienst des Servers nutzen möchte. Dieses
Segment wird mit gesetztem SYN-Flag versendet, als Zeichen, dass eine neue Verbindung aufgebaut werden soll. Es enthält außerdem den Port auf dem der Server auf die Verbindung wartet,
sowie den eigenen Port, auf dem seinerseits der Client Daten empfangen kann. Des Weiteren
wird die ISN (hier 1415531521) übertragen. Da noch keine Daten empfangen wurden, ist die
Window-Size noch gleich dem Startwert (hier 4096). Auch die Möglichkeit der Mitteilung der
MSS (1024) wird hier genutzt.
Der Client ändert nach dem Versand seinen Zustand von CLOSED in SYN SENT.
13
Client
Segment 1
Server
SYN 14155315
21
:1415531521
(0)
<mss 1024>
1 (0)
21:182308352
SYN 18230835
1024>
ss
m
<
,
22
15
ack 141553
Segment 3
ack 18230835
Segment 2
22
Abbildung 5: TCP 3-Way-Handshake
2. Hat der Server dieses Segment empfangen, versendet er ein Segment, ebenfalls mit gesetztem
SYN-Flag, in dem er seine ISN (1823083521) bekannt gibt. Außerdem muss er die ISN des
Clients bestätigen, indem er bei gesetztem ACK-Flag ISN+1 als Bestätigungsnummer zurückschickt. Auch der Server teilt dem Client eine MSS von 1024 mit. Die Mitteilung der eigenen
ISN und die Bestätigung der ISN des Clients geschieht in einem Segment. Danach wechselt der
Server in den Zustand SYN RCVD.
Obiges gilt jedoch nur für den Fall, dass der Server im Status LISTEN auf eine Verbindung gewartet hat. War dies nicht der Fall, kann keine Verbindung aufgebaut werden. Der Server sendet
ein Segment mit gesetztem RST-Flag (s. Verbindungs-Reset), um die Verbindung abzubrechen.
3. Um den Verbindungsaufbau abzuschließen, muss nun auch der Client die ISN des Servers
bestätigen, indem wiederum dessen ISN+1 bei gesetztem ACK-Flag gesendet wird. Das SYNFlag ist nun nicht mehr gesetzt.
Nach dem Versand des dritten Segments, wechselt der Client in den Zustand ESTABLISHED.
Sobald der Server das 3. Segment empfängt, wechselt auch er in den Zustand ESTABLISHED.
Damit ist die Verbindung erfolgreich aufgebaut und es können Daten übertragen werden.
Der Client hat die Möglichkeit, zusammen mit dem ACK bereits die ersten Daten zu übertragen.
Der Sender des ersten Segments mit SYN-Flag (hier der Client) vollzieht einen aktiven Verbindungsaufbau (Active Open), der Server, der das zweite Segment schickt einen passiven (Passive Open).
Simultaner Verbindungsaufbau
In seltenen Fällen, kann es auch vorkommen, dass zwei Hosts nahezu gleichzeitig versuchen, eine Verbindung aufzubauen. Dazu müssten aber beide Hosts den Port des jeweils anderen kennen.
Bei einem simultanen Verbindungsaufbau entfällt die Unterscheidung zwischen Server und Client.
Beide senden ein Segment mit SYN-Flag und der jeweiligen ISN (wie oben unter 1. beschrieben).
Dieses SYN Segment wird von beiden Hosts empfangen und bestätigt. Nach dem Empfang dieser
14
Client
Segment 1
Server
FIN 14155315
22:141553152
2 (0) ack 1823
083522
Segment 2
23
ack 14155315
FIN 18230835
Segment 4
22:182308352
2 (0) ack 1415
ack 18230835
531523
Segment 3
23
Abbildung 6: TCP Verbindungsabbau
Bestätigung ist die Verbindung aufgebaut. Für den Verbindungsaufbau werden in diesem Fall also 4
Segmente benötigt.
4.3.2 Verbindungsabbau
Verbindungsabbau per Half Close
Während für den Verbindungsaufbau im Normalfall drei Segmente benötigt werden, sind es beim
Verbindungsabbau vier. TCP-Verbindungen arbeiten im Fullduplex-Betrieb, das heißt, in beide Richtungen können unabhängig voneinander Daten verschickt werden. Beim Beenden einer Verbindung
müssen beide Richtungen separat getrennt werden. So kann durch den Half Close eine Seite ihre
Verbindung beenden, aber noch beliebig lange Daten von der Gegenseite empfangen. Es gibt in der
Praxis aber nur wenige Anwendungen, die diese Möglichkeit nutzen, eine davon, rsh, wird im Abschnitt “Anwendung des Half-Close” beschrieben. Wie auch beim Verbindungsaufbau wird zwischen
aktivem Verbindungsabbau (Active Close, Sender des ersten FIN) und passivem Verbindungsabbau
(Passive Close, Sender des zweiten FIN) unterschieden.
In Abbildung 6 ist diese Art des Verbindungsabbaus dargestellt.
1. Einer der beiden Hosts, auch hier ist es wieder in den meisten Fällen der Client, vollzieht den
so genannten Active Close, indem er ein Segment mit gesetztem FIN-Flag versendet. Das kann
auch das Segment sein, mit dem die letzten Daten verschickt wurden.
Nach dem Versand dieses Segmentes wechselt der Client vom Status ESTABLISHED in den
Status FIN WAIT 1.
2. Empfängt der Server ein Segment mit gesetztem FIN-Flag bestätigt er dessen Empfang, benachrichtigt die Anwendung, dass die Gegenseite die Verbindung beenden möcht und wechselt
in den Zustand CLOSE WAIT.
15
Nach dem Empfang des ACK wechselt der Client vom Zustand FIN WAIT 1 in den Zustand
FIN WAIT 2, um hier auf ein FIN des Servers zu warten.
3. Die Server-Anwendung kann, aufgrund des einseitigen Verbindungsabbaus, jetzt weiterhin Daten verschicken und sobald sie ebenfalls die Verbindung trennen möchte sendet sie ihrerseits
ein FIN. Danach wechselt sie in den Zustand LAST ACK.
4. Der letzte Schritt ist die Bestätigung des FIN und der Wechsel in den Zustand TIME WAIT.
Hier verbleibt der Client für die Zweifache Maximum Segment Lifetime (MSL) bevor er dann
den Status CLOSED annimmt. Der Server wechselt direkt nach dem Empfang des ACK in den
Zustand CLOSED.
Anwendung des Half Close
Eine Anwendung, die die Möglichkeit des Half Close nutzt, ist Remote Shell (rsh), welche Kommandos auf anderen Rechner ausführt. Dabei wird die Standard-Eingabe per TCP zu dem entfernten
Rechner kopiert und dessen Ausgabe auf dem Terminal des Client-Rechners ausgegeben. Nach dem
Kopieren der Standard-Eingabe beendet rsh die Richtung zu dem Rechner, um ihm zu signalisieren,
dass die Eingabe beendet ist, und er beginnen kann das Kommando auszuführen. Da die Verbindung
nur in einer Richtung geschlossen ist, kann der Rechner die Ausgabe des Kommandos ohne Probleme
zurückschicken. Danach beendet auch er die Verbindung.
Simultaner Verbindungsabbau
In Analogie zum Verbindungsaufbau ist es beim Abbau möglich, wenn auch eher zufällig, dass beide
Hosts nahezu gleichzeitig die Verbindung beenden möchten. Dabei wechseln beide nach dem Senden
des FIN-Segments in den Zustand FIN WAIT 1 und von dort aus nach Empfang und Bestätigung des
FIN in den Zustand CLOSING. Nachdem die Rechner die Bestätigung empfangen haben, wechseln
sie in den Zustand TIME WAIT. Bei einem simultanen Verbindungsabbau müssen also beide Seiten
zuerst die zweifache MSL abwarten, bevor sie den Zustand CLOSED annehmen.
Verbindungs-Reset
In einigen Fällen wird eine Möglichkeit gebraucht, um eine Verbindung abzubrechen. TCP ermöglicht
dies durch das Setzen des RST-Flags im TCP-Header. Ein Reset wird oft versendet, wenn dem Port
in der Verbindungsanfrage kein Prozess zugeordnet ist, beziehungsweise ein zugeordneter Prozess
nicht im Zustand LISTEN auf eine Verbindung wartet. Empfängt ein Host, nachdem er das erste SYN
versendet hat, ein Segment mit gesetztem RST-Flag, kann der User darüber informieren werden, dass
keine Verbindung möglich ist.
Es ist beiden Hosts möglich, eine Verbindung zurückzusetzen anstatt sie auf die oben beschriebene
Weise zu beenden. In diesem Fall werden alle Daten verworfen die noch zum Versand anstanden und
die Verbindung unmittelbar getrennt. Man spricht dann von einem Abortive Release im Gegensatz zu
dem oben beschriebenen Orderly Release.
16
Auch in dem Fall von halb-offenen (Half-Open) Verbindungen wird ein RST versendet. Eine Verbindung wird als halb-offen bezeichnet, wenn eine Seite die Verbindung ohne Kenntnis der anderen Seite
beendet oder abgebrochen hat. Das ist zum Beispiel der Fall, wenn einer der beiden Rechner abstürzt
oder er ohne vorheriges Runterfahren ausgeschaltet wird. Solange der andere Rechner keine Daten
übertragen will, wird er nicht merken, dass der Kommunikationspartner nicht mehr empfangsbereit
ist. Dieses Problem entsteht oft bei Client-Server-Verbindungen, wenn der User sich nicht die Mühe
macht, die Programme, die TCP verwenden, ordnungsgemäß zu beenden. Da der Server in den meisten Fällen von sich aus keine Daten versendet, bemerkt er nicht, dass der Rechner neu gestartet wurde.
Verwendet der User ein entsprechendes Programm erneut, wird eine neue Verbindung aufgebaut. Auf
diese Weise können viele halb-offene Verbindungen entstehen. In dem Fall, dass der Server doch von
sich aus Daten über eine solche Verbindung senden will, antwortet der Client, der nichts mehr mit
den empfangenen Verbindungsdaten anfangen kann, mit einem RST-Segment.
4.3.3 Zustandsübergangsdiagramm
Im Zustandsübergangsdiagramm sind alle Regeln für den Verbindungsauf- und -abbau zusammengefasst (s. Abb. 7). Die Zustandsübergänge, die ein Client normalerweise vollzieht, sind fett und die des
Servers gestrichelt markiert. Oberhalb der Pfeile ist notiert, welches Ereignis einen Übergang auslöst
und unterhalb wie darauf reagiert werden soll.
TIME WAIT oder 2 MSL Wait State
Der Zustand TIME WAIT wird auch als 2 MSL Wait State bezeichnet. Die Verbindung muss für die
zweifache MSL in diesem Zustand verharren, in dem alle verspäteten Segmente verworfen werden.
Dadurch wird sichergestellt, dass keine verspäteten Segmente als Teil einer neuen Verbindung fehlinterpretiert werden.
Quiet Time
Es kann vorkommen, dass ein Host, während er sich in der TIME WAIT-Phase befindet, abstürzt,
innerhalb von 2 MSL Sekunden rebootet und eine neue Verbindung aufbaut. In diesem Fall können
verspätete Segmente ebenfalls als Teil der neuen Verbindung interpretiert werden. Um diesen Fall
auszuschließen, gibt es das Quiet Time Concept, das besagt, dass ein Rechner nach einem Neustart
MSL Sekunden warten muss, bevor er eine neue Verbindung aufbauen darf.
4.4 Datenübertragung
Sobald beide Hosts den Status ESTABLISHED erreicht haben, können Daten in beide Richtungen
über das Netzwerk übertragen werden. Auch in den Zuständen FIN WAIT und CLOSE WAIT (nach
einem Half-Close) ist eine Datenübertragung möglich, hier aber nur in eine Richtung. In diesem Abschnitt wird immer vom Zustand ESTABLISHED ausgegangen, sofern nichts anderes erwähnt wird.
17
Abbildung 7: TCP Zustandsübergangsdiagramm [7]
18
Bei genauer Betrachtung der TCP-Segmente lassen sich diese in zwei Bereiche unterteilen. In Segmente, die interaktive Daten enthalten (Interaktiver Datentransfer zum Beispiel bei Anwendungen wie
RLogin, SSH, TELNET, etc.) und solche, die dem Dateitransfer dienen (Bulk Datentransfer bei Anwendungen wie FTP, SMTP, HTTP, etc.). Während Segmente beim interaktiven Datentransfer meist
nur wenige Byte groß sind, sind Bulk-Daten-Segmente häufig größtmöglich. Eine 1991 von Caceres
durchgeführte Studie [10] ergab, dass ca. 90% der Segmente weniger als 10 Byte an Nutzdaten enthalten.
Die unterschiedlichen Anforderungen beider Anwendungsbereiche an die Transportschicht führten zu
unterschiedlichen Algorithmen für den Umgang mit den Daten. Algorithmen, die beim interaktiven
Datentransfer eingesezt werden, versuchen, die Segmentanzahl und damit den durch deren Header
entstehenden Overhead zu reduzieren. Solche, die beim Bulk-Datentransfer zum Einsatz kommen,
haben einen hohen Durchsatz zum Ziel.
Im Folgenden werden zuerst einige Gesichtspunkte der zuverlässigen Datenübertragung und dann die
Algorithmen für die beiden Bereiche beschrieben.
4.4.1 Verbindungssicherheit
TCP gewährleistet die Verbindungssicherheit unter anderem dadurch, dass empfangene Segmente
bestätigt werden müssen. Bestätigungen erfolgen kumulativ, das heißt, dass jeweils das letzte korrekt
empfangene Byte bestätigt wird. Es gibt keine Möglichkeit den Verlust eines Segmentes explizit mitzuteilen. Um dennoch auf der Senderseite einen Segmentverlust feststellen zu können, bestätigt der
Empfänger bei jedem außerhalb der erwarteten Reihenfolge empfangenen Segment das letzte korrekt
empfangene Byte erneut. Auf eine solche duplizierte Bestätigung können Algorithmen wie Slow Start
entsprechend reagieren.
Sowohl die Daten, als auch deren Bestätigung können während des Transportes durch das Netz verloren gehen. Aus diesem Grund wird ein Retransmission Timer verwendet, um Daten erneut zu versenden, wenn innerhalb einer vorgeschriebenen Zeit keine Bestätigung eintrifft.
Da sich der Durchsatz des Netzes ändern kann (durch unterschiedlich starke Belastung oder sich
ändernden Routen durch das Netz) ist ein fest vorgegebener Retransmission-Timeout-Value (RTO)
nicht praktikabel. Um diesen Wert an die Netzgeschwindigkeit anzupassen, wird die Round-TripTime (RTT) so oft wie möglich gemessen, um daraus den RTO zu berechnen (s. unten).
Trifft für ein Segment keine Bestätigung innerhalb von RTO Sekunden ein, wird das Segment erneut übertragen und die RTO verdoppelt, da das Netz stark ausgelastet scheint. Das Segment wird
so lange neu übertragen und die RTO verdoppelt (ab einem Wert von 64 Sekunden bleibt die RTO
konstant), bis entweder eine Bestätigung für dieses Segment eintrifft, oder 9 Minuten verstrichen sind
(Exponential Backoff ). Im ersten Fall wird die RTT und damit auch der RTO neu berechnet, da die
Netzauslastung scheinbar abgenommen hat. Im zweiten Fall wird die Verbindung mittels RST vom
Sender beendet.
Berechnung von RTT und RTO
Die RTT ist die Zeit, die von dem Versenden eines Segments bis zum Empfang von dessen Bestätigung verstreicht. Um diese Zeitspanne zu bestimmen, wird ein 500ms Timer verwendet. Mit einem
19
Zähler wird bestimmt, wie oft dieser Timer zwischen Versand eines Segmentes und dessen Bestätigung abläuft. Da der Timer relativ zum Systemstart und nicht zum Versand des Segmentes abläuft,
erfolgt die erste Erhöhung des Zählers zwischen 1ms und 500ms nach dem Segmentversand. Die
Messung ist daher nicht sehr genau und kann auch trotz gleicher Zeiten Schwanken. Aus diesem
Grund wird der Wert durch die folgende Formel geglättet, wobei M die aktuelle Messung und R den
berechneten Wert bezeichnet.
R = α · R + (1 − α) · M, mit 0 ≤ α ≤ 1
Ein empfohlener Wert für α ist 0.9, das heißt, eine neue Messung geht zu 10% in die Berechnung ein.
Die meisten TCP-Implementierungen verwenden nur einen Zähler pro Verbindung, das schränkt die
Messung der RTT in einigen Fällen ein. Werden beispielsweise zwei Segmente kurz nacheinander
verschickt, kann nur für das erste die RTT berechnet werden, da der Zähler schon in Gebrauch ist,
wenn das zweite Segment versendet werden soll. Ebenfalls problematisch ist die Messung von Segmenten, die erneut übertragen wurden. Ein ACK kann hier nicht eindeutig zugeordnet werden, da
es verspätet von der ersten Übertragung eingetroffen sein kann oder erst von der zweiten. In diesen
Fällen wird die Berechnung verworfen.
Der RTO wird aus dem Wert R mittels eines Faktor β berechnet, für den RFC 793 einen Wert von 2
empfiehlt.
RT O = β · R
Nachdem es zu einem Timeout gekommen ist, darf die RTO aufgrund des Exponential Backoff nicht
neu berechnet werden. Erst nachdem wieder eine Bestätigung eingetroffen, ist werden weitere RTTMessungen vorgenommen.
4.4.2 Interaktiver Datentransfer
Beim interaktiven Datentransfer werden nur kleine Datenmengen transportiert. Bei Konsolenanwendungen wie RLogin führt jeder Tastendruck zu zwei Segmenten in denen jeweils 1 Byte an Daten
transportiert werden (so genannten Tinygrams), sowie zwei Segmenten zur Bestätigung: Beim Druck
des Anwenders auf eine Taste wird ein Segment generiert, was vom Server zunächst durch ein weiteres Segment bestätigt wird. Anschließend wird dem Anwender die Auswirkung des Tastendrucks
in einem dritten Segment mitgeteilt (Häufig ist das die Darstellung des Zeichens in der Konsole),
welches abschließend ebenfalls bestätigt wird. Für dieses eine Zeichen werden also 80 Byte an TCPHeadern und lediglich 2 Byte an Daten transportiert. Dies macht deutlich, wie wichtig Algorithmen
sind, die versuchen die Anzahl der versendeten Pakete zu reduzieren. Zwei dieser Algorithmen werden im Folgenden beschrieben.
Delayed Acknowledgments
Delayed Acknowledgments sind dafür verantwortlich, dass ein oben beschriebenes Szenario im Normalfall nicht vorkommt. Es ist nicht notwendig, dass der Empfang eines Segmentes umgehend bestätigt
wird. Stattdessen besteht die Möglichkeit, bis zu 200 ms darauf zu wartet, ob Daten zurückgeschickt
20
werden müssen. Ist das der Fall, kann das ACK zusammen mit den Daten übertragen und so ein Segment eingespart werden. Für das obige Beispiel bedeutet dies, dass die Segmente 2 und 3 zu einem
zusammengefasst werden.
Für die Zeitmessung wird ein Timer benutzt, der alle 200 ms relativ zum Rechnerstart abläuft. Das
bedeutet, dass die Bestätigungen zwischen 1 und 200 ms hinausgezögert werden können. Treffen in
diesem Zeitraum Daten zum Versand ein, werden diese bereits vor Ablauf des Timers zusammen mit
dem ACK verschickt. Falls nach Ablauf des Timers keine Daten angefallen sind, wird das ACK in
einem eigenen Segment gesendet.
Nagle Algorithmus
Nagles Algorithmus [4] versucht, die Netzwerkbelastung, die durch den Versand von vielen Tinygrams entsteht, zu vermeiden. Für den Fall, dass eine Empfangsbestätigung für vorrangehende Daten
noch nicht eingetroffen ist, werden alle von der Anwendung an die TCP-Schicht weitergegebenen
Daten zurückgehalten. Trifft die Empfangsbestätigung ein, kann so eine größere Datenmenge versendet werden.
Nagles Algorithmus passt sich somit an die Geschwindigkeit und Auslastung des Netzes an. Kommen
bei einem wenig belasteten Netz ausstehende Segment-Bestätigungen schnell an, werden wartende Daten ebenso schnell verschickt. Ist dagegen die Netzauslastung hoch, werden Daten gesammelt
und in großen Segmenten mit großen Zeitabständen verschickt, um dadurch das Netzwerk zu entlasten. Während bei der Datenübertragung in schnellen Netzen die Auswirkung dieses Algorithmus bei
Konsolenanwendungen kaum spürbar ist, äußert sich sein Einsatz in langsamen Netzen dadurch, dass
Zeichen bei Konsolenanwendungen verzögert und in Schüben dargestellt werden.
Es gibt auch Anwendungen, für die Nagles Algorithmus hinderlich ist. Das X Windows System ist
eine solche. Hier müssen auch kleine Datenmengen, zum Beispiel die Bewegung des Mauszeigers,
sofort versendet werden. Aus diesem Grund kann durch die TCP NODELAY-Socket-Option der Algorithmus deaktiviert werden.
4.4.3 Bulk-Datentransfer
Beim Bulk-Datentransfer werden häufig viele Daten in eine Richtung versendet. Die eingesetzten Algorithmen müssen also dafür sorgen, dass die Kapazität des Netzwerkes ausgelastet wird, ohne es zu
überlasten.
Bei TCP werden solche Algorithmen der Fluss- und Überlastkontrolle zugeordnet. Flusskontrolle
sorgt empfängerseitig dafür, dass der Sender den Empfänger nicht mit Daten überfluten kann, Überlastkontrolle kontrolliert den Datenfluss auf der Senderseite.
Sliding Window
Das Sliding-Window-Protokoll [8] gehört zur Flusskontrolle. Über das Window-Size-Header-Feld
kann der Empfänger dem Sender mitteilen, wie viele Daten noch empfangen werden können, bevor
der Empfangspuffer voll ist (Offered Window). Aus dieser Angabe und der Datenmenge, die er bereits
21
durch Window-Size angegebene
Fenstergröße
(offered window)
1
2
3
4
bereits bestätigt
5
6
7
gesendet,
nicht bestätigt
8
9 10 11 12 13 14 15 16 17
noch nutzbar
(usable window)
erst nach
Fensterbewegung
nutzbar
Abbildung 8: TCP Sliding Window
ohne Bestätigung verschickt hat, kann der Sender errechnen, wie viel Speicherplatz im Empfangspuffer noch verfügbar ist (Usable Window). Alle zusätzlich versendeten Segmente würden nur unnötig
das Netzwerk belasten, da der Empfänger sie aufgrund eines vollen Empfangspuffers löschen müsste.
Die Größe und Position des Fensters verschiebt sich im Laufe einer Datenübertragung (s. Abb. 8). Es
beginnt immer nach der letzten bestätigten Sequenznummer und hat die durch Window Size angegebene Größe. Durch die Bestätigung eines Segmentes verschiebt sich also der linke Rand des Fensters
nach rechts und verkleinert es auf diese Weise. Es kann wieder vergrößert werden, wenn die Anwendung Daten aus dem Puffer gelesen hat und bei dem nächsten Segment in Richtung Sender die
aktualisierte Window Size angegeben wird. Ist die Anwendung nicht in der Lage, die Daten schnell
genug aus dem Puffer zu lesen (zum Beispiel bei einem langsamen Rechner), wird durch ein Empfangsfenster von 0 Byte der Datentransfer vorübergehend gestoppt. Wenn die Anwendung einen Teil
des Puffers geleert hat, wird durch die TCP-Schicht das letzte ACK mit einer aktualisierten Fenstergröße (ein so genanntes Window Update) gesendet.
Wie jedes andere Segment auch, kann dieses ACK verloren gehen. Ohne weitere Beachtung würde
dies zu einem Deadlock führen: Der Sender wartet auf ein Window Update, um weitere Daten schicken zu können, und der Empfänger wartet auf neue Daten. Um dies zu verhindern, wurde der Persist
Timer eingeführt. Dieser erlaubt es dem Sender in festgelegten Abständen (5, 6, 12, 24, 48, 60 Sekunden) eine Window Probe bestehend aus dem nächsten Byte an den Empfänger zu schicken, um zu
überprüfen, ob sich die Window Size geändert hat. Ist dies nicht der Fall wird das vorherige Byte erneut
bestätigt und eine Fenstergröße von 0 Byte angegeben. Falls das Empfangsfenster wieder geöffnet ist,
wird das neue Byte bestätigt und eine positive Fenstergröße angegeben, so dass der Datentransfer
wieder aufgenommen werden kann.
Durch die Verwendung der fenster-orientierten Flusskontrolle kann es zu dem als Silly Window Syndrome bekannten Problem kommen. Es entsteht, wenn der Empfänger ein sehr kleines Fenster anbietet
(ohne darauf zu warten ein größeres Fenster anbieten zu können), oder der Sender kleine Datenmengen sofort sendet ohne auf weitere Daten zu warten. Dieses Problem zu verhindern ist Aufgabe beider
Seiten. So darf der Empfänger nur ein neues Empfangsfenster anbieten, wenn es mindestens um eine MSS oder um die Hälfte seines Empfangspuffers vergrößert werden kann. Der Sender darf nur
dann Segmente versenden, wenn ein maximales Segment zum Versand ansteht, mit einem Segment
mindestens die Hälfte des angebotenen Fensters gefüllt wird oder keine Bestätigung für ein vorangehendes Segment aussteht.
22
Die Größe des Empfangspuffers beträgt bei heutigen Implementierungen mindestens 4096 Byte, einige Verwenden größere Puffer von 8192 oder sogar 16384 Byte.
Slow Start
Das Sliding Window sorgt zwar dafür, dass der Empfänger nicht mit Segmenten überflutet wird, es
kann aber nicht verhindern, dass Daten möglicherweise an einem Router verloren gehen. Dies kann
passieren, wenn ein Router aufgrund eines langsamen Netzes Daten zwischenspeichern muss und sein
Speicher überfüllt ist. Dann muss er Segemente verwerfen, was den Durchsatz einer TCP-Verbindung
stark beeinträchtigen kann.
Aus diesem Grund müssen aktuelle TCP-Implementierungen einen Algorithmus namens Slow Start
unterstützen, der die Menge der Daten, die ins Netzwerk abgegeben werden, kontrolliert. Für diesen
Zweck wird ein weiteres Fenster, das Congestion Window (cwnd) auf der Senderseite verwaltet und
mit dem Wert der MSS initialisiert. Nach jedem ACK wird dieses Fenster um eine MSS erhöht. Dadurch wächst das Congestion Window exponentiell (wird das erste Segment bestätigt können zwei
weitere gesendet werden, werden auch diese bestätigt 4, usw.). Der Sender kann maximal bis zum
Minimum von cwnd und Window Size übertragen ohne eine Bestätigung zu erhalten.
Der Sender überwacht den Empfang der ACKs und sieht den Empfang der dritten gleichen Sequenznummer als Anzeichen dafür an, dass mindestens ein Segment wegen der zu hohen Senderate auf dem
Weg zum Empfänger verloren gegangen ist. Aus diesem Grund wird das Congestion Window wieder
auf die Größe von einer MSS gesetzt und Slow Start beginnt erneut.
Durch das exponentielle Wachstum wird sehr schnell eine optimale Netzauslastung erreicht. Ebenso schnell kann es aber zu Segmentverlusten kommen, die vorübergehend zu einer sehr geringen
Netzauslastung führen. Aus diesem Grund wird Slow Start zusammen mit einem weiteren Algorithmus, Congestion Avoidance, implementiert.
Congestion Avoidance
Congestion Avoidance [9] versucht, besser als Slow Start auf einen Segmentverlust zu reagieren. Er
basiert auf der Annahme, dass nur etwa 1% aller Segmente fehlerhaft übertragen werden. Die restlichen Segmente gehen durch überfüllte Router-Puffer verloren. Congestion Avoidance benötigt eine
weitere Variable, ssthresh, die Anfangs mit 65.535 Bytes initialisiert wird. Tritt jetzt ein Segmentverlust auf, wird ssthresh auf die Hälfte der Current Window Size (Minimum aus Window Size und
cwnd, jedoch mindestens 2 MSS) gesetzt. Für den Fall, dass der Segmentverlust durch einen Timeout
festgestellt wurde, wird cwnd auf eine MSS reduziert. Andernfalls (Segmentverlust wurde durch duplizierte ACKs festgestellt) wird cwnd auf sstresh gesetzt, da der Empfang eines ACK impliziert, dass
nach wie vor Segmente beim Empfänger ankommen und so der Datenfluss auf eine geringere Menge
aber nicht ganz zurück gesetzt werden muss.
Die Vergrößerung des Sendefensters (cwnd) ist nun abhängig davon, welcher Algorithmus verwendet wird. Ist cwnd kleiner oder gleich ssthresh, wird Slow Start verwendet. Danach wird Congestion
Avoidance verwendet, wodurch das Sendefenster lediglich um 1/cwnd vergrößert wird, wenn eine
Bestätigung eintrifft.
23
5 Zusammenfassung
In der vorliegenden Arbeit wurden nach der Einführung einiger Grundlagen die beiden Transportprotokolle UDP und TCP aus dem TCP/IP-Protokollstapel vorgestellt. Die vielen verschiedenen Anwendungen im Bereich des Internets führten zur Entwicklung von zwei sehr verschiedenen Protokollen. Das verbindungslose und unzuverlässige UDP wird häufig bei Echtzeit-Anwendungen (Ton,
Bild oder Sprache) eingesetzt. Auch der Client-Server-Bereich, mit einem Kommunikationsschema
nach dem Anfrage-Antwort Prinzip gehört zum Einsatzbereich von UDP. TCP wird immer dann eingesetzt, wenn zuverlässige Datenübertragung erforderlich ist. Dies ist vor allem beim Dateitransfer
(FTP, HTTP, SMTP, usw.) der Fall. Aber auch Konsolenanwendungen wie TELNET oder SSH verwenden TCP.
Nach der Vermittlung einiger Grundlagen wurde zuerst das wesentlich einfachere der beiden Protokolle, UDP, beschrieben. Hauptaugenmerk lag hier bei der Erläuterung des Header-Aufbaus, dem
Zusammenspiel von UDP mit IP und ARP, sowie zwei Anwendungen, bei denen UDP als Transportptotokoll zum Einsatz kommt.
Bei der Beschreibung von TCP wurde ebenfalls zuerst auf den Aufbau des Headers eingegangen.
Danach wurde das Verbindungsmanagement beschrieben, um abschließend Algorithmen für die Optimierung der Übertragunsleistung vorzustellen.
Literatur
[1] Postel, J., User Datagram Protocol, RFC 768, 1980.
[2] Postel, J., Transmission Control Protocol, RFC 793, 1981.
[3] Plummer, D. C., An Ethernet Address Resolution Protocol, RFC 826, 1982.
[4] Nagle J., Congestion Control in IP/TCP Internetworks, RFC 896, 1984.
[5] Srinivasan, R., RPC: Remote Procedure Call Protocol Specification Version 2, RFC 1831, 1995.
[6] Schulzrinne, H., Casner, S., Frederick, R., Jacobson, V., RTP: A Transport Protocol for RealTime Applications, RFC 1889, 1996.
[7] Stevens, W. R., TCP/IP Illustrated, Volume I, Adison-Wesley, Massachusetts, 1997, ISBN 0201-63346-9 (v.1).
[8] Tanenbaum, A. S., Computer Networks, Prentice Hall PTR, Amsterdam, 1996, ISBN 0-13349945-6.
[9] Kurose, J. F., Ross, K. W., Computer Networking: A topdown approach featuring the Internet,
Adison-Wesley, Massachusetts, 2001, ISBN 0-201-47711-4.
[10] Caceres, R., Danzig, P. B., Jamin, S. und Mitzel, D. J., Characteristics of Wide-Area TCP/IP
Conversations, Computer Communication Review, vol. 21(4), pp. 101-112, September 1991.
24
Herunterladen