TCP/UDP und Varianten Seminar ... - Informatik 4
TCP/UDP und Varianten Seminar ... - Informatik 4
TCP/UDP und Varianten Seminar ... - Informatik 4
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
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