02.02.2015 Aufrufe

TCP/UDP und Varianten Seminar ... - Informatik 4

TCP/UDP und Varianten Seminar ... - Informatik 4

TCP/UDP und Varianten Seminar ... - Informatik 4

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

Rheinisch-Westfälische Technische Hochschule Aachen<br />

Lehrstuhl für <strong>Informatik</strong> IV<br />

Prof. Dr. rer. nat. Otto Spaniol<br />

<strong>TCP</strong>/<strong>UDP</strong> <strong>und</strong> <strong>Varianten</strong><br />

<strong>Seminar</strong>: Kommunikationsprotokolle SS02<br />

Dirk Sabath<br />

Matrikelnummer: 228752<br />

Betreuung:<br />

Markus Fidler<br />

Lehrstuhl für <strong>Informatik</strong> IV, RWTH Aachen


Inhaltsverzeichnis<br />

1 Einleitung 3<br />

2 Gr<strong>und</strong>lagen 3<br />

3 User Datagram Protocol 4<br />

3.1 Der <strong>UDP</strong>-Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

3.2 Fragmentierung durch IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

4 Transmission Control Protocol 7<br />

4.1 Der <strong>TCP</strong>-Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

4.2 Verbindungsaufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

4.3 Verbindungsabbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

4.3.1 Verbindungsabbau per Half Close . . . . . . . . . . . . . . . . . . . . . . . 10<br />

4.3.2 Simultaner Verbindungsabbau . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

4.3.3 Reset einer Verbindung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

4.4 Datentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

4.5 Verbindungssicherheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

4.5.1 Erkennung von Segmentverlust auf Senderseite . . . . . . . . . . . . . . . . 13<br />

4.5.2 Erkennung von Segmentverlust auf Empfängerseite . . . . . . . . . . . . . . 14<br />

4.5.3 Roll-Back-N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

5 Flow- <strong>und</strong> Congestioncontrol in <strong>TCP</strong> 15<br />

5.1 Sliding Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

5.2 Nagle Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

5.3 Delayed Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

5.4 Slowstart/Congestion Avoidance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

6 <strong>Varianten</strong> von <strong>TCP</strong> 18<br />

6.1 <strong>TCP</strong>-Tahoe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

6.2 <strong>TCP</strong>-Reno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

6.3 SACK-<strong>TCP</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

2


1 Einleitung<br />

Seit der Entstehung des ARPANET, dem Vorläufer des Internet, hat die Bedeutung heterogener Netzwerke<br />

stark zugenommen. Dabei auftretende Schwierigkeiten sind nicht nur das Vernetzen von sehr<br />

unterschiedlichen Rechnersystemen, sondern auch die verschiedenen Netzwerktopologien <strong>und</strong> die<br />

dadurch entstehende unterschiedliche Güte von Verbindungen im Netzwerk. Auch ist eine einheitliche<br />

Programmierschnittstelle unabdingbare Voraussetzung für ein heterogenes Netzwerk, denn es<br />

wird sich kaum ein Mensch die Arbeit machen wollen, sich für jedes erdenkbare System <strong>und</strong> jeden<br />

vorstellbaren Anwendungszweck mit anderen Schnittstellen vertraut zu machen. Daher wird ein flexibles<br />

Protokoll wie das Transmission Control Protocol (<strong>TCP</strong>) benötigt, ein verbindungsorientiertes<br />

Protokoll, dass die Dienste des Internet Protokoll (IP) nutzt, <strong>und</strong> eine Programmierschnittstelle zur<br />

Verfügung stellt, die es möglich macht, unabhängig von der Netzwerktopologie <strong>und</strong> der Verbindungsqualität<br />

zu programmieren. <strong>TCP</strong> ist mittlerweile für alle gängigen Systeme verfügbar, meistens ist es<br />

schon mehr oder weniger fest im Betriebssystem verankert.<br />

Da es in der Vergangenheit wegen zu hohem Datenverkehr zu Verbindungszusammenbrüchen kam,<br />

wurde es notwendig <strong>Varianten</strong> von <strong>TCP</strong> zu entwickeln, die vor allem zusätzliche Fluss- <strong>und</strong> Staukontrolle<br />

beherrschen, um Überlastungen des Netzwerks vorzubeugen.<br />

Neben dem verbindungsorientiertem <strong>TCP</strong> gibt es noch ein verbindungsloses Gegenstück, das User<br />

Datagram Protocol (<strong>UDP</strong>). Auf dieses Protokoll möchte ich zuerst eingehehen, da es nicht nur zeitlich<br />

vor <strong>TCP</strong> (wenn auch nur kurz) liegt, sondern auch auf der technischen Seite, allein schon aufgr<strong>und</strong><br />

der Verbindungslosigkeit einfacher ist.<br />

2 Gr<strong>und</strong>lagen<br />

Um einen Überblick zu erhalten, was ein in der Transportschicht angesiedeltes Protokoll leisten soll,<br />

ist ein kurzer Blick auf die Transportschicht unabdingbar.<br />

Die Transportschicht ist im ISO/OSI-Referenzmodell als vierte Schicht zwischen der Vermittlungsschicht<br />

<strong>und</strong> der Sitzungsschicht angesiedelt. Die <strong>TCP</strong>/IP Protkokollsuite macht eine grobere Aufteilung<br />

in nur vier Schichten, welche im Folgendem erläutert werden:<br />

Die unterste Schicht ist die Link-Schicht. Sie beinhaltet sehr hardwarenahe Dienste, wie zum Beispiel<br />

Netzwerkkartentreiber. Hier ist auch Address Resolution Protokoll (ARP) [5] enthalten, das für die<br />

Zuordnung von IP-Adressen zu Hardwareadressen (MAC) zuständig ist. Es schickt dazu ein Ethernet-<br />

Frame an alle Hosts in einem Netzwerk, in dem die MAC-Adresse zu einer IP-Adresse angefordert<br />

wird (ARP-Request), woraufhin sich der entsprechende Host meldet, indem er mit einem Ethernetframe<br />

mit der entsprechenden MAC- sowie IP-Adresse antwortet (ARP-Reply). ARP verwendet ein<br />

Cache, um Adressen für einen gewissen Zeitraum zwischenzuspeichern.<br />

In der Netzwerkschicht ist das Internet Protocol (IP) <strong>und</strong> das Internet Control Message Protocol<br />

(ICMP) interessant, denn vor allem auf die Dienste von IP baut die Transportschicht auf. Sie beinhaltet<br />

<strong>TCP</strong> <strong>und</strong> <strong>UDP</strong> <strong>und</strong> stellt den in der Application-Schicht zu findenden Anwendungen, wie z.B.<br />

FTP, Email, usw. einen Dienst bereit. Einer der Hauptgründe, Netzwerk- <strong>und</strong> Transportschicht zu<br />

3


trennen, besteht darin, dass die Netzwerkschicht nicht klar von der verwendeten Netzwerkarchitektur<br />

<strong>und</strong> Hardware getrennt ist, mit der Transsportschicht steht ein von all dem unabhängiger Dienst bereit.<br />

Wichtig ist hierbei die Unterscheidung zwischen Protokollen, die die Datagramme von Host zu Host<br />

versenden, wie IP eines ist <strong>und</strong> Protokollen, die Datagramme zwischen zwei Prozessen versenden,<br />

wie <strong>TCP</strong> <strong>und</strong> <strong>UDP</strong>. Bei ersterem werden IP-Datagramme immer zum nächsten Router weitergeleitet,<br />

der das Datagram anhand der angegebenen Adresse weiterleitet, bis der entsprechende Host erreicht<br />

ist, <strong>und</strong> das Paket vom Netzwerk entfernt. IP definiert für jedes Datagram eine maximale Lebensdauer<br />

eines Datagrams, die Time to live (TTL). Diese beim Versand auf einen Startwert gesetzt, <strong>und</strong> bei<br />

jedem Hop, den das Datagram passieren muss, wird sie dekrementiert. Sollte sie 0 werden, so wird<br />

das Datagram verworfen.<br />

In der Transportschicht gilt es, zwei Protokollarten zu unterscheiden. Die verbindungslosen Protokolle,<br />

wie <strong>UDP</strong> eines ist, bauen keine explizite Verbindung zum Ziel auf. Es wird angenommen, das der<br />

Zielrechner immer erreichbar <strong>und</strong> bereit ist, Daten zu empfangen. <strong>UDP</strong> ist ausserdem ein unsicherer<br />

Dienst (unreliable), d.h. es wird nicht sichergestellt, dass Daten, die versendet wurden, auch ihr Ziel<br />

erreichen. Es ist leicht einzusehen, dass diese Protokolle einen recht einfachen Aufbau haben.<br />

Dem gegenüber stehen die verbindsorientierten Protokolle wie <strong>TCP</strong>. Sie bauen immer eine Verbindung<br />

zum Zielrechner auf <strong>und</strong> stellen sicher, dass der Zielhost zu einer Kommunikation bereit ist.<br />

<strong>TCP</strong> ist ein sicherer Dienst (reliable), d.h. hier wird dem Prozess, der <strong>TCP</strong> benutzt, garantiert, dass alle<br />

Daten ihr Ziel erreichen. Beiden Protokollen ist gemein, dass sie von mehreren Prozessen gleichzeitig<br />

benutzt werden können. Durch Multiplexing werden eingehende Daten den Prozessen zugeordnet.<br />

Dazu werden den Prozessen Ports zugeteilt, anhand derer die Prozesse identifiziert werden.<br />

3 User Datagram Protocol<br />

Das User Datagram Protocol (<strong>UDP</strong>) [6] ist ein sehr einfaches Protokoll. Es arbeitet verbindungslos,<br />

das heisst es wird keine Verbindung zu einem Host aufgebaut. Anfallende Daten werden von <strong>UDP</strong><br />

einfach abgeschickt, ohne das sichergestellt wird, ob das Ziel überhaupt erreichbar ist, oder ob das<br />

Ziel bereit, ist Daten zu empfangen. Daten werden von beliebiger Größe in Form von Datagrammen<br />

verschickt. Wenn man sich nun vor Augen führt, dass ein Netzwerk keine unendlichen Kapazitäten<br />

besitzt, wird schnell klar, dass sich der Programmierer durchaus Gedanken über die Grösse der zu<br />

versendenden Daten machen muss. Übersteigt die entstehende Datagrammgrösse einen bestimmten,<br />

netzwerkabhängigen Grenzwert, so erfolgt eine Fragmentierung durch das in der Vermittlungsschicht<br />

agierende Internet Protokoll (IP). Doch dazu später mehr.<br />

<strong>UDP</strong> stellt einem Benutzerprozess einen Dienst bereit. Da möglicherweise mehrere Prozesse diesen<br />

Dienst in Anspruch nehmen mo¨chten, benutzt <strong>UDP</strong> Portnummern, um Prozesse zu identifizieren, für<br />

welche die Daten bestimmt sind (Multiplexing). Die Portnummern sind aus dem Bereich 0-65535 frei<br />

wählbar. Einige sind jedoch bestimmten Anwendungen standardmässig zugewiesen, allerdings nicht<br />

verbindlich.<br />

4


3.1 Der <strong>UDP</strong>-Header<br />

Zunächst werfen wir einen Blick auf den Header eines <strong>UDP</strong>-Datagramms. Ein Datagramm besteht<br />

aus einem Kopf mit vier Feldern dem ein Datenblock variabler Grösse folgt. Die Felder des Kopfs<br />

sind wie folgt besetzt:<br />

Abb. 3.1 Der <strong>UDP</strong>-Header<br />

Source Port (Bit 0 bis 15, insgesamt 16 Bit)<br />

In dieses Feld schreibt der Absender seine Portadresse, an welche der Zielhost dem sendenden<br />

Prozess Daten zurückschicken kann. Es ist nicht zwingend notwendig, dass der Host auf diesem<br />

Port bereit ist, Daten zu empfangen.<br />

Destination Port (Bit 16 bis 31, insgesamt 16 Bit)<br />

Dieses Feld beinhaltet den Port des Empfängers für den die Daten bestimmt sind. Anhand dieser<br />

Nummer wird das Datagramm einem Benutzerprozess zugeordnet.<br />

Länge des <strong>UDP</strong>-Datagramms (Bit 32 bis 47, insgesamt 16 Bit)<br />

Hier ist die Länge des Datagramms in Byte angegeben. Die Länge beinhaltet das gesamte Datagramm,<br />

also Kopf <strong>und</strong> Daten zusammen. Die Angabe der Länge ist red<strong>und</strong>ant, da sie sich<br />

sehr leicht aus der angegebenen Länge im IP-Header errechnen lässt. Da bei IP für die Länge<br />

ebenfalls ein 16-Bit Feld reserviert ist, sieht man, dass die Datenmenge in einem Datagramm<br />

beschränkt ist auf 65535 Byte - 20 Byte (IP-Header) - 8 Byte (<strong>UDP</strong>-Header) = 65507 Byte.<br />

Checksum des <strong>UDP</strong>-Datagramms<br />

Die Angabe ist optional, es wird aber empfohlen sie immer zu verwenden. Wird sie nicht verwendet,<br />

so sind die 16 Bit mit Nullen zu füllen. Wird sie benutzt, berechnet sie sich wie folgt:<br />

Dem eigentlichen Header wird ein Pseudo-Header vorangestellt, der die IP-Adresse des Absenders<br />

<strong>und</strong> des Empfängers (jeweils 32 Bit), 8 Bit Nullen, die Angabe des Protokolls (8 Bit)<br />

<strong>und</strong> die Länge des Datagramms (16 Bit). Header, Pseudo-Header <strong>und</strong> Datenteil werden dann<br />

als 16-Bit Wörter modulo 2 aufaddiert. Hat der Datenteil ungerade Länge, so wird er mit 8 Bit<br />

Nullen aufgefüllt. Das Ergebnis wird im Einerkomplement in das Feld geschrieben, daher ist<br />

5


es unterscheidbar, ob die Checksum 0 (es sind dann alle Bits gesetzt) ist oder gar keine Berechnung<br />

stattgef<strong>und</strong>en hat (kein Bit gesetzt). Man sieht, dass die Länge zweimal in die Berechnung<br />

der Checksum eingeht.<br />

Ist die Checksum fehlerhaft, so wird das Paket verworfen <strong>und</strong> es findet keinerlei Rückmeldung<br />

statt. Obwohl die Checksum optional ist, sollte sie jedoch immer berechnet werden, da<br />

durch sie Modifikationen (durch fehlerhafte Verbindung o.ä.) erkannt werden können. Allerdings<br />

kann eine Vertauschung von 16-Bit Wörtern nicht erkannt werden, ein Nachteil der recht<br />

einfachen Berechnung.<br />

3.2 Fragmentierung durch IP<br />

Die Datenmenge, die in einem Paket im Netzwerk verschickt werden kann, ist durch die in der Link-<br />

Schicht festgelegte Maximum Transfer Unit (MTU) [2] beschränkt. Daher wird ein sehr grosses Datagramm<br />

unweigerlich zu einer Fragmentierung durch IP in der Vermittlungsschicht führen. Da diese<br />

Fragmentierung, d.h. eine Aufteilung des Datagramms in mehrere IP-Datagramme, im Normalfall zu<br />

einem Overhead, bedingt durch zusätzlichen Platz für IP-Header, führt, sollte sie vermieden werden 1 .<br />

Da eine Fragmentierung an jedem Punkt, den das Datagramm passieren muss, geschehen kann, ist die<br />

kleinste MTU in der Verbindung zwischen den Hosts zu bestimmen, um die Fragmentierung unterbinden<br />

zu können. Dies kann durch setzen des DF-Bit (Do not fragment) im IP-Header <strong>und</strong> senden eines<br />

Datagramms der Grösse der ausgehenden MTU geschehen. Kommt eine Fehlerrückmeldung durch<br />

ICMP, so kann man es mit einem Datagramm der im ICMP Paket angegebenen MTU des nächsten<br />

Hop erneut versuchen. Sollte die Angabe im ICMP Paket nicht erfolgt sein, so setzt man die Grösse<br />

des Datagramms beliebig herab.<br />

Durch Fragmentierung kann ein weiterer Effekt zwischen <strong>UDP</strong> <strong>und</strong> ARP auftreten. Wenn der ARP<br />

Cache leer ist, dann impliziert ein verschicktes Datagramm einen ARP-Request, <strong>und</strong> es wird ein Reply<br />

erwartet, um den anderen Host adressieren zu können. Da IP die Fragmente sehr schnell generiert,<br />

wird zu jedem Fragment ein ARP-Request abgeschickt (ARP-flooding). Nach der ersten Antwort auf<br />

eine Anfrage wird das letzte Fragment gesendet, da ein Fragment im Puffer überschrieben wird, wenn<br />

ein neues ankommt. Es treten keine Fehlermeldungen durch ICMP auf, da ICMP den Benutzerprozess<br />

nicht darüber informieren kann. IP muss nach dem Ablauf eines Timeouts das empfangene Segment<br />

verwerfen, damit es nicht zu einem Überlauf des Empfangspuffers kommt. Das fragmentierte Datagramm<br />

muss danach erneut vom Benutzerprozess gesendet werden.<br />

Aus dem Obigem erkennt man, das <strong>UDP</strong> keine Verbindungssicherheit garantieren kann, <strong>und</strong> deshalb<br />

für Dienste, die dies erfordern, nicht sehr geeignet 2 ist. So eignet sich <strong>UDP</strong> wegen des geringen<br />

Verwaltungsaufwand eher für Anwendungen, die eine schnelle Verbindung erfordern, aber bei denen<br />

Verluste von Daten nicht sehr bedeutend ist.<br />

1 Im Prinzip ist es hier egal, wer die Fragmentierung durchführt, klar ist, dass sie durchgeführt werden muss, da ein zu<br />

grosses Datagram nicht von der Link-Schicht nicht versendet wird<br />

2 nicht sehr geeignet heisst, es ist möglich, jedoch nötigt es dem Programmierer nur zusätzliche Arbeit auf<br />

6


4 Transmission Control Protocol<br />

Das Transmission Control Protocol (<strong>TCP</strong>) arbeitet im Gegensatz zu <strong>UDP</strong> verbindungsorientiert, d.h.<br />

es wird zwischen zwei Hosts, die miteinander kommunizieren wollen, eine Verbindung aufgebaut.<br />

Dadurch kann Verbindungssicherheit realisiert werden. So wird ein Dienst zur Verfügung gestellt, der<br />

die zugr<strong>und</strong>eliegende Netzwerkarchitektur den Benutzerprozessen transparent macht, d.h. es ist für<br />

eine Anwendung irrelevant, wie das Netzwerk über das kommuniziert wird aufgebaut ist.<br />

<strong>TCP</strong> teilt zu versendende Daten selbstständig in Segmente auf, die einzeln verschickt werden. Es<br />

ergibt sich ein Byte-Strom orientierter Dienst. Eine Anwendung kann also kontinuierlich Daten versenden,<br />

was eine gewisse Ähnlichkeit mit dem Schreiben <strong>und</strong> Lesen von Dateien hat.<br />

Zuverlässigkeit erhält eine <strong>TCP</strong>-Verbindung durch das Bestätigen jedes Segments. Werden Segmente<br />

nicht bestätigt, so müssen sie wiederholt werden. Dadurch können auftretende Übertragungsfehler im<br />

Netzwerk behoben werden. Es gibt aber auch Mechanismen, die die versuchen, durch Überlastung<br />

eines Hosts oder des Netzwerks hervorgerufene Fehler zu vermeiden. Diese Mechanismen zählt man<br />

zur Fluss- <strong>und</strong> Staukontrolle. Effiziente Mechanismen zur Fluss- <strong>und</strong> Staukontrolle sind in den <strong>Varianten</strong><br />

von <strong>TCP</strong>, wie <strong>TCP</strong> Tahoe, <strong>TCP</strong> Reno <strong>und</strong> <strong>TCP</strong>-SACK, implementiert.<br />

<strong>TCP</strong> arbeitet im Fullduplex Modus, d.h. es können gleichzeitig in beide Richtungen über eine Verbindung<br />

Daten gesendet werden. So wird meistens der Empfang von Segmenten in Segmenten bestätigt,<br />

die selbst wiederum Daten enthalten (Piggyback).<br />

4.1 Der <strong>TCP</strong>-Header<br />

Betrachten wir zunächst die Form der Segmente, die von <strong>TCP</strong> verschickt werden.<br />

Ein Segment besteht aus einem Header, dessen Grösse zwischen 20 Byte <strong>und</strong> 60 Byte variiert. Dem<br />

angehängt ist der Datenteil von ebenfalls variabler Grösse. Im Header enthalten sind (in dieser Reihenfolge):<br />

16 Bit Source Port<br />

16 Bit Destination Port<br />

Wie <strong>UDP</strong> verwendet auch <strong>TCP</strong> Ports um eingehende Segmente den Anwendungsprozessen<br />

zuzuordnen.<br />

32 Bit Sequence Number<br />

Die hier angegebene Sequenznummer zeigt an, an welche Stelle das Segment im Datenstrom<br />

einzusortieren ist. Durch diese Nummer wird es möglich, Pakete in falscher Reihenfolge zuzulassen,<br />

da sie so in die ursprüngliche Reihenfolge gebracht werden können. Bei einem Verbindungsaufbau<br />

ist hier die Startnummer des Stroms, die Initial Sequence Number (ISN), angegeben.<br />

Sie wird nach dem Booten mit einer Zufallszahl initialisiert.<br />

7


32 Bit Acknowledgement Number<br />

In diesem Feld wird die Nummer des Segments angegeben, das als nächstes erwartet wird. Die<br />

Angabe ist immer vorhanden, auch wenn sie manchmal nur für eine Richtung gebraucht wird.<br />

Dies ist der Fall, wenn die Verbindung nur in eine Richtung Daten verschickt.<br />

4 Bit Header Length<br />

Da die Länge des Headers variabel ist, ist diese Angabe zwingend, um den Datenteil des Segments<br />

erreichen zu können.<br />

6 Bit reserviert<br />

Diese Bits werden bisher nicht verwendet.<br />

6 Bit Options<br />

Hier sind Flags in der folgenden Reihenfolge anzutreffen:<br />

– URG : Ist dieses Bit gesetzt, so wird signalisiert, dass der Urgent Pointer gesetzt wurde.<br />

– ACK : Dieses Bit zeigt an, das die Acknowledgement Number gesetzt ist. Ein Segment<br />

mit gesetztem ACK-Bit wird im folgendem als Quittung bezeichnet.<br />

– PSH : Ist das Bit gesetzt, so müssen die enthaltenen Daten so schnell wie möglich an den<br />

zuständigen Benutzerprozess weitergeleitet werden.<br />

– RST : Dieses Bit veranlasst das Zurücksetzen der Verbindung.<br />

– SYN : Dieses Bit zeigt dem Gegenüber an, das eine Verbindung aufgebaut werden soll.<br />

Es werden die Sequenznummern synchronisiert.<br />

– FIN : Mit diesem Bit signalisiert der Sender, dass er keine weiteren Daten zu versenden<br />

hat <strong>und</strong> die Verbindung schliessen möchte.<br />

16 Bit Window Size<br />

Hier wird der freie Platz im Empfangspuffer angegeben. Diese Angabe wird für die Verfahren<br />

zur Fluss- <strong>und</strong> Staukontrolle benötigt.<br />

16 Bit Checksum<br />

Die Checksum berechnet sich analog zu der Checksum eines <strong>UDP</strong>-Datagramms.<br />

16 Bit Urgent Pointer<br />

Der Urgent Pointer zeigt auf das letzte Byte dringender Daten im Datenteil. Diese Daten werden<br />

dann umgehend, d.h. unabängig von der Reihenfolge im Datenstrom, an den Benutzerprozess<br />

weitergeleitet.<br />

Am Ende des Headers können weitere Optionen angehängt sein. Diese Optionen haben einen<br />

zugeordneten Typ, mit dem man die Option identifiziert wird. Ist eine Option nur ein Flag, dann<br />

reicht die Angabe des Typs, sonst muss nach dem Typ die gesamte Länge der Option angegeben<br />

werden, worauf dann die eigentliche Option folgen kann. Die gesamte Länge ist ein Vielfaches<br />

von 4 Byte. Sämtliche möglichen Typen können [8] entnommen werden. In der ursprünglichen<br />

Spezifikation[7] sind folgende Optionen enthalten:<br />

8


– End Of Option List (Typ 0)<br />

Diese Option markiert das Ende der Optionenliste im Header<br />

– No Operation (Typ 1)<br />

Diese Option dient zum Auffüllen der Gesamtlänge aller Optionen auf ein Vielfaches von<br />

4 Bytes<br />

– Maximum Segment Size (MSS) (Typ 2)<br />

Die Länge dieser Option ist 4 Bytes, denn es wird hier die maximal erlaubte Segmentgrösse<br />

in 2 Bytes angegeben.<br />

Der Datenteil in einem <strong>TCP</strong> Segment ist optional.<br />

4.2 Verbindungsaufbau<br />

Es gibt zwei Möglichkeiten eine Verbindung aufzubauen. Die erste Möglichkeit ist, dass die Verbindung<br />

von einem Host initiiert wird. Die zweite Möglichkeit ist der simultane Verbindungsaufbau, bei<br />

dem zwei Hosts quasi gleichzeitig, d.h. der zweite Host initiiert ebenfalls eine Verbindung zum ersten<br />

Host noch bevor die erstere Verbindungsanforderung eingetroffen ist.<br />

Im ersteren Fall schickt der Initiator ein Segment mit gesetztem SYN-Bit. Dieser Host vollzieht ein<br />

active open. Dieser Schritt wird im Normalfall von einem Client ausgeführt, daher soll er ab jetzt<br />

auch hier so genannt werden. In dem ersten Paket mit dem SYN-Flag gibt er als Sequenznummer<br />

seine Initial Sequence Number (ISN) an. Die ISN ist dabei die erste Sequenznummer die verwendet<br />

wird. Der gegenüberliegende Host führt ein passive open aus. Er wird hier ab jetzt Server genannt.<br />

Er quittiert 3 die ISN des Clients, <strong>und</strong> ausserdem ist das SYN-Flag gesetzt, um anzuzeigen, dass er<br />

den Verbindungsaufbau erwidert. Der Client quittiert wiederum die ISN des Servers. Diese Art des<br />

Verbindungsaufbau nennt sich Three-Way Handshake.<br />

Beim simultanen Verbindungsaufbau wird dagegen der Austausch von vier Segmenten benötigt, um<br />

die Verbindung herzustellen. Hier führen beide Hosts ein active open durch, in dem sie fast gleichzeitig<br />

Segmente mit gesetztem SYN-Bit <strong>und</strong> ihrer ISN verschicken. Nach dem Empfang dieser Segmente<br />

senden die Hosts Quittungen, mit denen sie die ISN des Gegenübers bestätigen Nach Empfang dieser<br />

Quittungen ist die Verbindung hergestellt. Der simultane Verbindungsaufbau geschieht eher zufällig,<br />

im Normalfall erfolgt eine einseitige Verbindungsanforderung.<br />

Eine zentrale Rolle bei der Synchronisation der Sequenznummern übernimmt dabei die ISN. Es ist anzustreben,<br />

dass jede Verbindung eine eigene ISN zugeteilt bekommt, damit sie sich nicht gegenseitig<br />

beeinflussen. Schliesslich kann man sich vorstellen, dass ein Host abstürzt <strong>und</strong> eine neue Verbindung<br />

mit den gleichen Verbindungsdaten aufgebaut wird. Kommen alte Segmente verspätet an, so kann es<br />

passieren, dass ein altes Segment fälschlicherweise akzeptiert wird. Daher wird die ISN regelmässig<br />

per Timer <strong>und</strong> bei jedem Verbindungsaufbau iteriert. So soll sie nach [7] alle 4 Microsek<strong>und</strong>en inkrementiert<br />

werden. Da die ISN eine 32 Bit Zahl ist, wird sie nach ca. 4,5 St<strong>und</strong>en überlaufen. Unter der<br />

3 Quittung bezeichnet ein Segment mit gesetztem ACK-Bit <strong>und</strong> entsprechender ACK-Nr.<br />

9


Voraussetzung, dass die maximale Lebensdauer eines Segments kürzer ist, kann so eine Zweideutigkeit<br />

ausgeschlossen werden.<br />

Durch das Setzen der MSS-Option im Header können sich die Hosts beim Verbindungsaufbau mitteilen,<br />

welche die grösste von ihnen akzeptierte Segmentgröße ist.<br />

Wie oben bereits erwähnt, werden die Prozesse über einen Port adressiert. Sollte wider Erwarten auf<br />

dem Zielhost der Verbindunsanfrage kein Prozess auf dem adressierten Port lauschen, wird ein Reset<br />

gesendet, siehe dazu auch den nächsten Abschnitt.<br />

Ein Reset wird ebenfalls gesendet, wenn unerwartet Acknowledgements für Verbindungsanforderungen<br />

ankommen. Dies kann durch unterschiedliche Routen im Netzwerk entstehen. Sollte eine Verbindungsanforderung<br />

einen langen Weg im Netzwerk eingeschlagen haben 4 , so trifft die Quittung<br />

beim Sender nicht rechtzeitig ein, was zur Wiederholung des SYN führt. Dieses SYN kann nun einen<br />

kürzeren Weg einschlagen, <strong>und</strong> eine Verbindung aufgebaut <strong>und</strong> wieder abgebaut werden, bevor das<br />

erste SYN sein Ziel erreicht hat. Wenn das erste SYN nun sein Ziel erreicht, wird es als erneuter<br />

Wunsch eines Verbindungsaufbaus betrachtet. Es wird dann quittiert, diese Quittung jedoch beim Initiator<br />

nicht mehr erwartet. Dazu muss der Weg des ersten SYN nur hinreichend lang sein, <strong>und</strong> das<br />

SYN darf nicht von IP aufgr<strong>und</strong> einer TTL von 0 verworfen werden.<br />

4.3 Verbindungsabbau<br />

4.3.1 Verbindungsabbau per Half Close<br />

Der Verbindungsabbau wird durch ein Half Close realisiert. Das bedeutet, dass eine Seite den Verbindungsabbau<br />

anfordert, wenn sie keine Daten mehr zu senden hat. Sie bleibt aber in einem Zustand,<br />

in dem sie noch Daten vom anderen Host empfangen kann. Der den Verbindungsabbau anfordernde<br />

Host führt einen active close durch. Man sieht, dass beide Richtungen der Fullduplex-Verbindung<br />

unabhängig voneinander geschlossen werden.<br />

Um die Senderichtung für einen Host zu schliessen, schickt dieser ein Segment mit gesetztem FIN-<br />

Flag an den anderen Host. Dieser quittiert den Empfang. Damit gilt eine Richtung der Verbindung<br />

als geschlossen. Der erstere Host befindet sich nun in einem Zustand, in dem er auf Daten oder ein<br />

Segment mit gesetztem FIN-Flag, das anzeigt, dass nun die Verbindung ganz abgebaut werden soll,<br />

wartet. Der Empfang dieses Segmentes wird wiederum bestätigt. Nun muss der Host zweimal die<br />

Länge der Maximum Segment Lifetime (MSL) warten. Danach gilt die Verbindung als vollständig abgebaut<br />

5 . Das Warten hat den Gr<strong>und</strong>, dass die Quittung für den Verbindungsabbau verloren gegangen<br />

sein kann. Da ein Paket nach Ablaufen der MSL verworfen wird, muss ein wiederholtes Segment<br />

mit FIN-Flag innerhalb von¡£¢¥¤§¦©¨¨© !#"%$&¨©'(() *+-,/.0 !#"<br />

eingetroffen<br />

sein. Dies hat zur Folge, dass innerhalb der MSL nach dem Booten eines Systems keine Verbindung<br />

aufgebaut werden sollte, da es sein kann, dass das System in diesem wartenden Zustand abgestürzt<br />

sein kann. Bei kurzer Bootzeit könnten sonst die Verbindungsparameter einer alten, nicht vollständig<br />

4 worauf <strong>TCP</strong> keinen Einfluss hat<br />

5 Das entspricht dem Zustand TIME WAIT in Abb. 4.1<br />

10


abgebauten Verbindung wiederverwendet werden. Nach dem Verbindungsaufbau muss den Prozessen<br />

ein End-Of-File (EOF) signalisiert werden, da diese von nun an nicht mehr auf den Datenstrom<br />

zugreifen können.<br />

4.3.2 Simultaner Verbindungsabbau<br />

Wie beim Verbindungsaufbau gibt es auch beim Abbau die Möglichkeit des simultanen Abbaus. Hierbei<br />

wird wiederum vorausgesetzt, dass beide Hosts gleichzeitig ein Segment mit gesetztem FIN-Bit<br />

abschicken. Diese Segmente werden dann von beiden Seiten wie beim einseitigen Verbindungsabbau<br />

quittiert. Auch warten beide Hosts 2*MSL bis sie die Verbindung als komplett aufgelöst betrachten.<br />

Insbesondere liegt hier kein Half Close vor, sondern beide Richtungen gelten als geschlossen.<br />

4.3.3 Reset einer Verbindung<br />

Neben einem Verbindungsabbau kann eine Verbindung auch zurückgesetzt werden. Dies geschieht,<br />

wenn ein Host ein Segment mit gesetztem RST-Bit sendet. Das wird notwendig, wenn Segmente<br />

empfangen werden, die nicht erwartet werden, weil sie z.B. aus einer alten Verbindung stammen oder<br />

eine zu lange Laufzeit hatten <strong>und</strong> schon wiederholt wurden, oder dass sie einer falschen Adresse<br />

zugeordnet wurden.<br />

11


Anschaulich werden Verbindungsauf- <strong>und</strong> abbau im State Transitions Diagram in Abb. 4.1 dargestellt[9].<br />

Abb.4.1 Das State Transition Diagram [9]<br />

12


4.4 Datentransfer<br />

Befindet sich die Verbindung im ESTABLISHED-Zustand im State Transition Diagram, oder nach<br />

entsprechendem Half Close im Zustand CLOSE WAIT oder FIN WAIT, so können über die Verbindung<br />

Daten verschickt werden 6 . Die Benutzerprozesse, die per <strong>TCP</strong> miteinander kommunizieren<br />

sehen die Verbindung als kontinuierlichen Datenstrom. Es ist für sie daher irrelevant, in welcher Form<br />

die Daten verschickt werden. Daher ist Aufgabe von <strong>TCP</strong>, die Daten so in Segmente aufzuteilen, dass<br />

das Netzwerk optimal genutzt wird 7 . Man kann zwei Arten des Datenaustauschs unterscheiden:<br />

1. Interaktiver Datenaustausch (Interactive Data Flow [9])<br />

Hierbei werden nur wenig Daten ausgetauscht, auf die aber in kurzer Zeit reagiert wird. Das impliziert<br />

das Segmente abgeschickt werden müssen, auch wenn nur sehr wenig Daten anstehen. Die Folge<br />

ist, dass die Datenmenge pro Segment im Vergleich zum Header verschwindend gering sein kann. Es<br />

entsteht ein grosser Overhead durch die Header.<br />

2. Nicht interaktiver Datenaustausch (Bulk Data Flow [9])<br />

Es wird hauptsächlich in eine Richtung gesendet (z.B. Dateitransfer). Es ist daher sinnvoll, die gesamte<br />

Kapazität des Netzwerks auszuschöpfen, ohne dabei die Verbindung zu überlasten, denn das<br />

würde zu unnötigem wiederholtem Senden von Segmenten führen.<br />

4.5 Verbindungssicherheit<br />

Abschliessend bleibt noch die Frage offen, was bei Verlust von Segmenten in einem Netzwerk geschieht.<br />

Da <strong>TCP</strong> eine zuverlässige Verbindung bereitstellt, muss dafür Sorge getragen werden, dass<br />

solche Verluste erkannt <strong>und</strong> Segmente gegebenenfalls wiederholt gesendet werden.<br />

4.5.1 Erkennung von Segmentverlust auf Senderseite<br />

Dafür wird in [7] auf der Senderseite ein Timer gefordert, vor dessen Ablauf eine Quittung eingetroffen<br />

sein muss. Geschieht dies nicht, so muss das Segment erneut übertragen werden. Es wird dazu<br />

ein Retransmission Timeout (RTO) berechnet. Diese Berechnung findet nicht für jedes Segment statt,<br />

vielmehr ist nur ein Timer pro Verbindung gefordert. Zunächst wird die Sample Ro<strong>und</strong> Trip Time<br />

berechnet, die einen Erwartungswert für die Umlaufzeit eines Segmentes angibt.<br />

¦©)21¥134657¦8)21¥19$;:¥


OG <strong>und</strong> UG bezeichnen eine definierte Ober- bzw. Untergrenze für den Timeout.Y<br />

bezeichnet einen<br />

Verzögerungsfaktor, der zwischen 1,3 <strong>und</strong> 2 liegen sollte [7], damit eine geringe Überschreitung der<br />

berechneten SRTT nicht sofort zu einer Wiederholung des Segments führt 8 . Der RTO enthält einen<br />

ganzzahligen Wert, da die Umlaufzeit der Segmente in Ticks gemessen wird. Die Ticks erfolgen üblicherweise<br />

in Abständen von 500ms. Es sei angemerkt, dass diese Ticks unabhängig vom Start einer<br />

Messung der RTT laufen, wodurch ein gemessener RTT-Wert davon abhängt, wieviel Zeit seit dem<br />

letztem Tick vergangen ist. Daher ist dieser Wert nicht eindeutig. Die Messung der Umlaufzeit geschieht<br />

mit einem Zeitstempel, dessen Wert der Empfänger in das Optionsfeld des Quittungssegments<br />

einträgt.<br />

<strong>TCP</strong> reagiert auf den Verlust eines Segments mit einer Verdoppelung der RTO bei jeder wiederholten<br />

Sendung des Segmentes, da das Netzwerk stark ausgelastet zu sein scheint. So würde dann eine<br />

Wiederholung des Segments bei gleichem RTO wahrscheinlich erneut zum Verlust führen. Dieses<br />

Vorgehen nennt man Exponential Backoff [9].<br />

Sollten nun wieder Quittungen eintreffen, so muss der RTO wieder angepasst werden, da sich die<br />

Netzwerkauslastung wieder normalisiert haben kann, <strong>und</strong> ein zu hoher Timeout dazu führt, das weitere<br />

Verluste erst sehr spät erkannt werden. Der Zeitpunkt der neuen Berechnung wird nach Karn’s<br />

Algorithmus [9] bestimmt. Dieser Algorithmus besagt, dass die RTT neu gemessen (<strong>und</strong> dann der<br />

RTO neu berechnet) wird, wenn nach erfolgreicher Wiederholung von Segmenten das erste neue Segment<br />

quittiert worden ist.<br />

4.5.2 Erkennung von Segmentverlust auf Empfängerseite<br />

Auf der Empfängerseite wird gefordert, bei Empfang eines Segmentes mit falscher Sequenznummer<br />

das letzte in der richtigen Reihenfolge empfangene Segment wiederholt zu quittieren. Das hat zur<br />

Folge, dass beim Sender die Quittung eines Segments mehrfach eintrifft. Der Sender kann so den<br />

Verlust eines Segments erkennen. Da es möglich ist, dass ein fehlendes Segment nur verspätet beim<br />

Empfänger eintrifft <strong>und</strong> eine Wiederholung daher unnötig ist, reagiert der Sender erst bei Empfang<br />

der dritten duplizierten Quittung. Dann hat der Sender dieses Segment zu wiederholen.<br />

4.5.3 Roll-Back-N<br />

Roll-Back-N [1] ist der einfachste Mechanismus zur Segmentwiederholung. Sollte der Retransmission-<br />

Timer ablaufen, bzw. der Sender die dritte duplizierte Quittung erhalten haben, dann werden alle nicht<br />

quittierten Segmente wiederholt. Dabei ist es nicht von Bedeutung, ob nachfolgende Segmente bereits<br />

erfolgreich empfangen wurden. Roll-Back-N arbeitet daher nicht sehr ressourcenschonend.<br />

Andere, effizientere Methoden zur Segmentwiederholung sind in <strong>Varianten</strong> von <strong>TCP</strong> implementiert.<br />

Sie werden in Kapitel 6 vorgestellt.<br />

8 Würde gerade eine unterdurchschnittliche RTT gemessen, so würde das Fehlen dieses Faktors sehr schnell zu einem<br />

tatsächlich nicht vorhandenem Übertragungsfehler führen<br />

14


5 Flow- <strong>und</strong> Congestioncontrol in <strong>TCP</strong><br />

<strong>TCP</strong> versucht das Netzwerk optimal auszulasten. Optimal auslasten heisst, nach einem erfolgreichem<br />

Verbindungsaufbau möglichst schnell den Datenfluss auf ein Maximum zu erhöhen, dabei aber nicht<br />

das Netzwerk zu überlasten. Dies geschieht in <strong>TCP</strong> mittels Flow- <strong>und</strong> Congestioncontrol.<br />

Zu Flowcontrol zählt man die Verfahren, die auf der Empfängerseite, zu Congestioncontrol die Verfahren<br />

die auf der Senderseite den Datenfluss beeinflussen. Dazu wird ein Sende- <strong>und</strong> Empfangsfenster<br />

benutzt. Das Empfangsfenster kann als abstrakte Darstellung des tatsächlich unbenutzten Platz im<br />

Puffer des Empfänger betrachtet werden. Daraus kann der Sender ableiten wieviel Daten er maximal<br />

versenden darf.<br />

Es ist nicht gefordert, dass jedes Segment einzeln quittiert wird. Quittungen können auch kumulativ<br />

versandt werden, d.h. das Eintreffen einer Quittung mit Sequenznummer n+1 betstätigt den Empfang<br />

aller Segmente bis zur Sequenznummer n. Es kann kein Verlust von Segmenten mit Sequenznummer<br />

stattgef<strong>und</strong>en haben, denn dann müssen duplizierte Quittungen, die den Empfang der Segmente<br />

bc ,<br />

bis zur Sequenznummer c-1 bestätigen, beim Sender eingehen.<br />

5.1 Sliding Window<br />

Im Sende- <strong>und</strong> Empfangsfenster können Segmente, die noch nicht quittiert wurden, nicht berücksichtigt<br />

werden. Daher hat der Sender sich zu merken, wieviel nicht quitterte Segmente welcher Grösse<br />

er verschickt hat. Daraus ergibt sich die von ihm maximal zu verschickende Datenmenge:<br />

hf(hi\jh(z{h|7h<br />

h(i/z{h<br />

de SU;Sgfh(ij;k;lnmoh d pqsr+St!#u>\vu\;\w2¦ƒ„]<br />

Das Sliding Window [9] gibt die Datenmenge an, die versendet werden kann, ohne dass der Empfängspuffer<br />

überlaufen wird. Es beginnt nach der letzten bestätigten Sequenznummer <strong>und</strong> hat die im Empfangsfenster<br />

angegebene Grösse. Werden Segmente quittiert so verschiebt sich das gesamte Fenster<br />

nach rechts, bis es wieder an der entsprechenden Sequenznummer beginnt. Dieses Fenster ist das<br />

Maximum an Daten, die der Sender verschicken darf. Der Sender muss aus oben genannten Gründen<br />

das Fenster anpassen, in dem er die linke Grenze (letzte Quittung) bis zur letzten verschickten Sequenznummer<br />

nach rechts verschiebt. Das übriggebliebene Fenster gibt das tatsächliche Maximum<br />

an Daten, die versendet werden können, an.<br />

Wenn der Sender das Maximum ausgeschöpft hat <strong>und</strong> der Empfänger seinen Empfangspuffer nicht<br />

rechtzeitig leeren konnte, so hat sich der Empfangspuffer vollständig gefüllt. Dann schickt der Empfänger<br />

eine Quittung für das letzte empfangene Segment, welches seinen Puffer gefüllt hat. Er teilt dem Sender<br />

mit, das sein Empfangsfenster die Grösse 0 erreicht hat. Der Sender hört auf Daten zu verschicken,<br />

da er weiss, dass der Empfangspuffer gefüllt ist. Damit der Sender den Datenversand wieder aufnehmen<br />

kann, muss der Empfänger den Sender über einen geänderten Füllgrad des Empfangspuffers<br />

informieren. Dies geschieht durch das Window Update. Das Window Update ist eine Quittung, die<br />

€‚<br />

15


nicht den Empfang eines neuen Segmentes bestätigt, sondern dem Sender mitteilt, dass sich das Empfangsfenster<br />

geändert hat. Damit der Empfänger erkennt, wann er wieder Daten empfangen <strong>und</strong> das<br />

Window Update verschicken kann, wird der Persist Timer [9] verwendet. Mit dem Sliding Window<br />

besteht die Gefahr, dass das Silly Window Phänomen [9] auftritt. Der Empfänger bietet in jeder Quittung<br />

den freien Platz in seinem Empfangspuffer an, welcher gegebenenfalls sehr klein werden kann.<br />

Der Sender richtet sich nach diesem Wert <strong>und</strong> sendet entsprechend kleine Segmente, auch wenn eine<br />

wesentlich grössere Menge an Daten zum Versand ansteht. Dadurch entsteht ein Overhead durch die<br />

Header der Segmente. Diesem Problem wird vorgebeugt, in dem gefordert wird, dass mindestens ein<br />

Segment mit maximaler Segmentgrösse (angegeben in der MSS-Option) verschickt werden kann.<br />

5.2 Nagle Algorithmus<br />

Während das Sliding Window versucht, eine Überlastung der kommunizierenden Hosts zu vermeiden,<br />

versucht der Nagle Algorithmus [4] eine unnötige Last auf dem Netzwerk zu vermeiden. Dieser<br />

Algorithmus wird verwendet, wenn nur wenig Daten zum Versenden anstehen, so dass versendete<br />

Segmente sehr klein sind. Klein heisst hier, dass der Overhead durch Header Relevanz besitzt. Solche<br />

kleinen Segmente werden als Tinygrams [9] bezeichnet. Der Nagle Algorithmus arbeitet dann wie<br />

folgt:<br />

Voraussetzungen:<br />

Dann<br />

Es steht ein Tinygram zum Versand an<br />

Es ist bisher keine Quittung für das zuletzt versendete Segment eingegangen<br />

Sammle weitere Daten die evtl. anfallen <strong>und</strong> füge sie dem Tinygram an<br />

Wenn die noch austehende Quittung eintrifft, dann sende das aus mehreren Daten zusammengesetzte<br />

Segment<br />

Der grosse Vorteil dieses Algorithmus ist, dass er selbstskalierend ist, d.h. wenn die Netzwerkauslastung<br />

gering ist (die Quittungen treffen schnell ein), werden Daten ohne grösse Verzögerung versendet.<br />

Ist das Netzwerk jedoch stark ausgelastet, so werden resourcenschonende grosse Segmente in grossen<br />

Abständen versandt, die dazu beitragen, dass sich die Netzwerklast wieder verringert. Aber dieser<br />

Algorithmus hat auch einen Nachteil, denn er ist für Anwendungen, die ihre Daten schnell benötigen,<br />

nicht einsetzbar (z.B. Echtzeitanwendungen).<br />

5.3 Delayed Acknowledgements<br />

Im Gegensatz zum Nagle Algorithmus setzt man mit Delayed Acknowledgements [9] auf der Empfängerseite<br />

an. Hat der Empfänger ein Segment erhalten, so wartet er eine gewisse Zeit, bis er die Quittung<br />

sendet. Fallen in dieser Zeit Daten an, die zurück an den Sender geschickt werden müssen, so können<br />

die Daten <strong>und</strong> die Quittung zusammen übertragen werden.<br />

16


5.4 Slowstart/Congestion Avoidance<br />

Ein Nachteil des Sliding Window ist, dass es zu Überlastungen an Knoten kommen kann, die auf dem<br />

Weg zum Empfänger passiert werden müssen, da diese keinen Einfluss auf die Grösse des Fensters<br />

ausüben können. Diesem Nachteil tritt Slowstart [9] entgegen. Auf der Senderseite wird die Eingangsrate<br />

von Quittungen beobachtet. Mittels Slowstart versucht man, die Ausgangsrate von Segmenten<br />

der Eingangsrate von Quittungen anzugleichen. Ein optimaler Zustand wird dann erreicht wenn der<br />

Sendkanal vollständig gefüllt ist.<br />

Abb. 5.1 Füllung des SendeKanals: 1)gering 2)optimal<br />

Slowstart versucht, die Kapazität des Kanals möglichst schnell vollständig auszunutzen, solange kein<br />

Segment verloren geht. Dazu benötigt Slowstart für jede Verbindung ein Congestionwindow, das zu<br />

Anfang der Verbindung mit 1 initialisiert wird. Für jede korrekt empfangene Quittung wird das Congestionwindow<br />

inkrementiert. …q† +!0>u\† 2(v‡ † a …ˆ† !0>u† £‡ † ‰$a:<br />

Dies führt zu einem exponentiellem Wachstum der Anzahl der Übertragenen Segmente, denn während<br />

des Sendens von Segmente treffen Quittungen für die zuletzt gesendeten Segmente ein. Sind z.B. 2<br />

Segmente verschickt worden, so kommen 2 Quittungen zurück, so dass sich die Grösse des Congestionwindow<br />

verdoppelt.<br />

Der Sender sendet dann Datenmenge = min[Empfangsfenster, Congestionwindow]. Dies führt recht<br />

schnell zu einem gefülltem Sendekanal, solange der Empfänger seinen Puffer schnell genug leeren<br />

kann. Sollte jedoch ein Segment verloren gehen, so ist das Congestionwindow wieder auf den Anfangswert<br />

zu setzen, <strong>und</strong> der Füllgrad des Sendekanals nimmt dementsprechend ab. Um eine solche<br />

Situation zu verhindern, arbeitet Slowstart in Kombination mit Congestion Avoidance. So wird ein<br />

Schwellwert SSThreshold eingeführt, der anfangs zu 65535 Bytes initialisiert wird [10]. Sollte das<br />

Congestionwindow kleiner sein als der Schwellwert, so wird das Fenster gemäss dem Slowstart Algorithmus<br />

erhöht. Ist der Schwellwert überschritten, so geht das Verfahren in Congestion Avoidance<br />

über. Dann gilt für die Erhöhung des Congestionwindow<br />

…q† !0>u† 2(v‡ † a …q† +!#>u† 2‡ † ‰$ :<br />

17<br />

…ˆ† !0>u† £v‡ †


Wenn man diese Formel mit dem gleichen Argument wie bei der Erhöhung beim Slowstart Algorithmus<br />

betrachtet, dann ergibt sich effektiv eine Erhöhung um 1. Sind z.B. zwei Pakete gesendet worden<br />

<strong>und</strong> die zugehörigen Quittungen eingetroffen, so ergibt sich für die Erhöhung des Congestionwindow<br />

…ˆ† !0>u† £v‡ † Ši\h‹Œ ¡s$D¡I5©Ž …ˆ† !0>u† £v‡ † ‘moj’$“:<br />

. Sollte es nun doch zu einem<br />

Verlust eines Segmentes kommen, so wird der Schwellwert SSThreshold angepasst<br />

F˜HJšL…ˆ† !0>u† £‡ † PRpˆsr+St+!‚u>\vu;\w7Z<br />

¡<br />

Das Congestionwindow muss ebenfalls anpasst werden, allerdings gilt es hier zu unterscheiden, ob<br />

ein Timeout vorliegt oder duplizierte Quittungen eingetroffen sind. Im letzteren Fall wird es auf den<br />

u>u\•”‚w–>u>”—<br />

gleichen Wert wie SSThreshold gesetzt. Da weiterhin Segmente ihr Ziel erreichen, ist es in diesem<br />

Fall sinnvoll den Datenfluss auf geringerem Niveau aufrecht zu erhalten. Im ersten Fall kann jedoch<br />

die Verbindung vollständig abgebrochen sein, <strong>und</strong> daher ist ein Übertragen von mehreren Segmenten<br />

hintereinander nicht sinnvoll. Das Staukontrollfenster wird auf 1 gesetzt, <strong>und</strong> die Verbindung fällt<br />

zurück in die Slowstart-Phase.<br />

6 <strong>Varianten</strong> von <strong>TCP</strong><br />

6.1 <strong>TCP</strong>-Tahoe<br />

Ein grosser Nachteil des einfachen Go-Back-N Verfahren ist, dass Segmente unter Umständen unnötig<br />

wiederholt werden. Das geschieht dann, wenn wirklich nur ein Segment bei der Übertragung verloren<br />

gegangen ist, später gesendete jedoch erfolgreich übertragen wurden. Durch die ausschliesslich<br />

positiven Quittungen ist es dem Empfänger nicht möglich, dem Sender mitzuteilen, welches Segment<br />

nicht empfangen wurde. Um diese Netzlast zu vermeiden muss man erkennen können, wann ein einzelnes<br />

Segment verloren gegangen ist, um dann nur dieses einzeln zu wiederholen.<br />

Der Verlust eines einzelnen Segmentes kann einerseits durch Überfüllung des Empfängerpuffers geschehen,<br />

andererseits werden im Netzwerk Router eingesetzt, die ebenfalls einer Überlastung unterliegen<br />

können. Dann werden von ihnen eintreffende Pakete verworfen. Da dadurch keine Daten mehr<br />

über das Netzwerk verschickt werden können, verwendet man in den Routern vermehrt das Verfahren<br />

Random Early Discard (RED). Dieses Verfahren verwirft mit zunehmender Wahrscheinlichkeit bei<br />

zunehmender Auslastung einzelne Segmente, um so einer Überlastung vorzubeugen.<br />

In der Variante <strong>TCP</strong>-Tahoe das Fast Retransmit Verfahren [9] implementiert. Es beruht auf der Annahme,<br />

dass der Empfang duplizierter Quittungen auf den Verlust eines einzelnen Segments deutet.<br />

Liegt jedoch ein Timeout vor, dann ist das Netzwerk überlastet, denn es kommen schliesslich auch<br />

keine Quittungen zurück. Es sind dann alle nicht quittierten Segmente erneut zu senden.<br />

Nach Empfang der dritten duplizierten Quittung wird von einem einfachen Übertragungsfehler ausgegangen.<br />

Mit dem Fast Retransmit Verfahren wird nur das Segment wiederholt, das auf das mehrfach<br />

quittierte Segment folgt. Hat der Empfänger nun dieses Segment empfangen, so quittiert er kumulativ<br />

18


alle Segmente die er nach dem Übertragungsfehler korrekt erhalten hat. Nach Empfang dieser Quittung<br />

beginnt der Sender wieder, Segmente ab dem quittierten Segment zu übertragen. Jedoch fällt die<br />

Verbindung zurück in den Slowstart-Modus, womit der Datenfluss sich enorm verringert.<br />

6.2 <strong>TCP</strong>-Reno<br />

Ein Nachteil des in <strong>TCP</strong>-Tahoe implentierten Fast-Retransmit Verfahren ist, dass die Verbindung<br />

nach einem durch duplizierte Quittungen gekennzeichneten Fehler zurück in den Slowstart-Modus<br />

geht. Die Tasache, dass einzelne Segmente verloren gehen, ist ein Hinweis darauf, dass der evtl. hohe<br />

Datenfluss nicht vollständig abgebrochen ist, sondern nur an seine obere mögliche Grenze stösst [9].<br />

Daher ist es nicht notwendig, den Datenfluss zu minimieren.<br />

In <strong>TCP</strong>-Reno tritt dieses Verhalten nicht auf, da nicht nur das Fast Retransmit Verfahren, sondern auch<br />

das Fast-Recovery Verfahren implementiert wurde. Dieses Verfahren soll den Datenfluss auf einem<br />

hohem Niveau halten. Wie oben vorgestellt, wird bei Slowstart/Congestion Avoidance der Schwellwert<br />

SSThresh verwendet, bis zu diesem das Congestionwindow bei empfangenen Quittungen verdoppelt<br />

wird. Dieser Wert wird bei einem Übertragungsfehler auf die Hälfte des Minimums aus dem<br />

Congestionwindow <strong>und</strong> dem Empfangsfenster gesetzt. Fast-Recovery arbeitet nun genauso wie Fast-<br />

Retransmit, nur wird hierbei der nach dem Übertragungsfehler neu gesetzte Schwellwert SSThresh<br />

als angemessener Wert für das Congestionwindow angesehen <strong>und</strong> deshalb auf diesen Wert gesetzt.<br />

So geht erstens die Verbindung nicht in den Slowstart-Modus, sondern das Congestionwindow wird<br />

gemäss des Congestion Avoidance Algorithmus inkrementiert, <strong>und</strong> zweitens wird der Datenfluss auf<br />

einem angemessenen Niveau erhalten. Sollten jedoch mehrere Segmente im übertragenen Fenster<br />

verloren gegangen oder die Wiederholung eines Segmentes ebenfalls fehlgeschlagen sein, dann wird<br />

auch hier in den Slowstart-Modus übergegangen.<br />

<strong>TCP</strong>-Reno ist heutzutage die am weitesten verbreitete Ausführung von <strong>TCP</strong>.<br />

6.3 SACK-<strong>TCP</strong><br />

In <strong>TCP</strong> mit Selctive Acknowledgements [3], kurz SACK-<strong>TCP</strong>, wird zusätzlich zu den positiven <strong>und</strong><br />

kumulativen Acknowledgements eine Option eingeführt, mit der Blöcke von Segmenten bestätigt<br />

werden können. Dazu werden zwei Headeroptionen benutzt. Zum einen ist das die SACK-permitted<br />

Option(Typ 4, Länge 2), mit der angezeigt wird, das SACK verwendet wird. Diese Option wird üblicherweise<br />

zusammen mit dem SYN-Flag beim Verbindungsaufbau gesetzt. Die zweite Option ist<br />

<strong>TCP</strong>-SACK(Typ 5, Länge variabel). In dieser Option werden Blöcke von Segmenten angegeben, die<br />

der Empfänger quittieren möchte. Diese Blöcke werden in der folgenden Form angegeben:<br />

1.Block: Sequenznummer des ersten Segments des 1.Blocks<br />

1.Block: Sequenznummer die auf das letzte Segment des 1.Blocks folgt<br />

19


. . .<br />

n.Block: Sequenznummer des ersten Segments des n.Blocks<br />

n.Block: Sequenznummer die auf das letzte Segment des n.Blocks folgt<br />

Da jeder Header maximal 40 Bytes an Optionen aufnehmen darf <strong>und</strong> jeder Block 64 Bit ( = 8Bytes,<br />

4Byte Anfangssequenznummer, 4 Byte folgende Sequenznummer) beansprucht, können höchstens 4<br />

Blöcke angegeben werden. Der Empfänger beobachtet ständig seinen Empfangspuffer. Soll nun ein<br />

Segment quittiert werden, geschieht das nach den folgenden Regeln:<br />

Ist das zu quittierende Segment in korrekter Reihenfolge eingetroffen ( d.h. vor allem kein<br />

fehlendes Segment vor diesem), so wird eine normale Quittung ohne SACK-Option verschickt.<br />

Sollte (genau) ein Segment vor diesem fehlen, so wird ein Segment mit SACK-Option versendet.<br />

In diesem Segment wird der Empfang des Segments vor dem fehlenden quittiert (eine<br />

übliche duplizierte Quittung). In der SACK-Option wird ein Block angegeben, in dem das empfangene<br />

Segment quittiert wird. Als erste Sequenznummer wird die auf das fehlende Segment<br />

folgende Sequenznummer angegeben.<br />

Sollten bereits mehrere Segmente fehlen, so wird wie im vorangegangenem Punkt vorgegangen,<br />

ausser das nun für jedes fehlende Segment ein Block eingetragen wird. Der i-te Block enthält<br />

dabei zuerst die auf das (Blöcke - i)-te fehlende Segment folgende Sequenznummer, danach die<br />

Sequenznummer des nächsten fehlenden Segments, bzw. die des zuletzt empfangenen Segments<br />

(der erste Block enthält die Nummer des zuletzt empfangenen Segments).<br />

Anhand dieser SACK-Optionen kann der Sender erkennen, welche Segmente nicht korrekt ausgeliefert<br />

wurden <strong>und</strong> diese selektiv wiederholen.<br />

<strong>TCP</strong>-SACK geht nach einem mehrfachen Übertragungsfehler nicht in den Slowstart-Modus zurück.<br />

Literatur<br />

[1] Fall, K., Floyd, S., Comparisons of Tahoe, Reno, and Sack <strong>TCP</strong>, Tech. Report, 1995<br />

[2] Ross Keith, Kames F. Kurose Computer Networking: A topdown approach featuring the Internet,<br />

Addison Wesley, 2001<br />

[3] Mathis et al., Selctive Acknowledgement Options, RFC 2018, 1996<br />

[4] Nagle,Congestion Control in IP/<strong>TCP</strong> Internetworks, RFC 896, 1984<br />

[5] Plummer, David C., An Ethernet Address Resolution Protocol, RFC 826, 1982<br />

20


[6] Postel, J., User Datagram Protocol, RFC 768, 1980<br />

[7] Postel, J., Transmission Control Protocol, RFC 793, 1981<br />

[8] Postel, J., The Magic Numbers in <strong>TCP</strong>/IP, RFC 1340, 1992<br />

[9] Stevens, W. Richard, <strong>TCP</strong>/IP Illustrated Volume I, Addison Wesley, 1994<br />

[10] Stevens et al., <strong>TCP</strong> Congestion Control, RFC 2581, 1999<br />

21

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!