TCP heisst "Transmission Control Protocol". Dieses Protokoll ist speziell dafür geeignet, grosse Dateien in kleinere Pakete zu unterteilen und diese mittels Pipelining über ein Netzwerk zu senden. Standartisiert ist TCP durch RFC 793, 1122, 1323, 2018 und 2581 (Downloads). TCP fügt dem darunterliegenden Inhalt einen Header vorne an, welcher folgendermassen aufgebaut ist:
| Byte | f | e | d | c | b | a | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | f | e | d | c | b | a | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0x00 | Source-Port | Destination-Port | ||||||||||||||||||||||||||||||
| 0x04 | Sequenz-Nummer | |||||||||||||||||||||||||||||||
| 0x08 | ACK-Nummer | |||||||||||||||||||||||||||||||
| 0x0c | Head-Länge | U | A | P | R | S | F | Empfänger-Fenstergrösse | ||||||||||||||||||||||||
| 0x10 | Checksum | Wichtige-Daten-Pointer | ||||||||||||||||||||||||||||||
| 0x14 | ... Optionen ... | |||||||||||||||||||||||||||||||
| 0x14 | ... Daten ... | |||||||||||||||||||||||||||||||
Der Source- und Destination-Port sind genau gleich belegt, wie bei UDP. Für einen Empfänger sind diese Daten sehr praktisch. Wenn er eine Antwort senden muss, vertauscht er einfach die beiden Einträge.
Die Sequenz- und ACK-Nummer wird wie folgt verwendet: Wenn der Client ein Paket sendet, so enthält Sequenz-Nummer die Byte-Position innerhalb der gesamten Datei, die er versendet, und ACK enthält einen Kontrollwert. Wenn nun der Server das Paket korrekt erhalten hat, so sendet er ein ACK-Paket zurück, welches als ACK-Wert das nächste zu sendende Byte (errechnet mittels Byte-Position plus Datenblock-Länge) enthält und als Sequenznummer den Kontrollwert von vorher. Dadurch kann der Client sehen, dass das Paket nun abgehakt werden kann, und er sieht zudem, ab welcher Byteposition er als nächstes senden muss.
Was genau passiert, falls Pakete verlorengehen zeigen die vier folgenden Szenarien (Standartisiert durch RFC 1122, 2581):
- Ein Paket kommt an, das genau an die bereits erhaltenen Daten anfügt: Warte eine halbe Sekunde, bis dass das nächste anfügende Paket kommt. kommt keines, so sende ein ACK mit der Nummer des nächsten erwarteten Bytes.
- Das zweite, erwartete Paket des ersten Falles kommt an: Sende sofort ein ACK, welches gleich beide Pakete abhakt.
- Ein Paket kommt an, das eine grössere Byte-Position enthält, als erwartet: Schicke dasselbe ACK wie vorhin nochmals. Puffere das Paket und merke dir, von wo bis wo nun eine Lücke besteht.
- Ein Paket kommt an, das die Lücke teilweise oder ganz ausfüllt: Sende sofort ein ACK, falls die Lücke von links her aufgefüllt wird.
Um eine TCP-Verbindung zu starten, wird ein sogenannter 3-Wege-Handshake ausgeführt:
- Der Client schickt ein SYN-Signal (S-Flag auf 1) mit der Sequenznummer, die als erste gelten soll (normalerweise 0) an den Empfänger.
- Bei Empfang der ersten Nachricht richtet der Server einen Puffer ein und schickt ein ACK-Signal zurück, wobei auch hier das SYN-Flag auf 1 gesetzt ist.
- Der Client empfängt diese Nachricht und sendet ein ACK-Signal, welches gegebenfalls bereits die ersten Daten enthält.
Um eine TCP-Verbindung zu beenden, werden 4 Schritte ausgeführt:
- Der Client schickt ein Paket mit dem gesetzten FIN-Flag (Anfrage auf Verbindungsabbruch).
- Der Server erhält diese Nachricht und antwortet zuerst mit einem ACK. Gleich darauf sendet er selbst ein FIN-Signal und leitet somit die Schliess-Prozedur ein.
- Der Client erhält irgendwann das FIN-Signal und sendet darauf ein ACK. Er weiss damit, dass der Server die Verbindung bei Erhalt des ACKs sofort schliessen wird. Der Client selbst wartet jedoch noch ein kleines Bisschen, bevor er selbst die Verbindung schliesst.
- Der Server erhält das ACK und schliesst die Verbindung.
Die Empfänger-Fenstergrösse gibt an, wieviel Platz der Empfänger noch in seinem Puffer übrig hat. Dadurch wird erreicht, dass der Sender den Empfänger nicht überlastet (Congestion-Control), denn dieser Wert wird bei jedem ACK zurückgegeben.
Zur Überlastungskontrolle gehört zudem eine Flusskontrolle (Flow-Control), bei welcher durch Abschätzung der Fenstergrösse erreicht wird, dass die Verbindung nicht überlastet wird. Die Pakete werden mittels GBN oder Selective Repeat in einem Fenster gepuffert. Die Fenstergrösse des Senders berechnet sich folgendermassen (das Fenster hat die Grösse (in Paketen) Congwin):
- TCP startet mit einer niedrigen Bandbreite: Congwin = 1.
- Erhöhe Congwin so lange, bis die Variable Threshold erreicht wird (normalerweise exponentielles Wachstum). Erhöhe daraufhin in kleinen Schritten.
- Sobald ein erstes Paket verlorenging, wird die Bandbreite wieder gedrosselt und die Variable Threshold gesenkt, dann wird wieder bei 1 angefangen.
Die Bandbreite, bzw, der Throughput einer TCP-Verbindung kann somit mittels einer einfachen Rechnung gemessen werden: Wenn während einer Round-Trip-Time w Pakete (Dies ändert sich natürlich mit der Variablen Congwin) verschickt werden konnten, jedes mit der Grösse M, so ist der Throughput = w*M/RTT.
Durch diese Art von Überlastungskontrolle wird implizit eine gewisse Fairness erreicht, auf jeden Fall wird niemand vollkommen übergangen. Es gibt verschiedene Fairnessformen, ein paar davon sind:
- Max-Min: Eine Menge von Verbindungen ist dann fair verteilt, wenn keine Verbindung schneller werden kann, ohne dass eine andere darunter leiden muss. Diese Fairness sollte eigentlich angestrebt werden, ist jedoch in einem dynamischen Netzwerk wie dem Internet praktisch unmöglich. Ausserdem kommt hier das Problem hinzu, dass nicht alle Verbindungsknoten die gleiche Übertragungsrate besitzen.
- Proportional: Die Übertragungsrate wird so aufgeteilt, dass, je mehr Links passiert werden müssen, umso weniger übertragen werden darf. Diese Fairness ist gut für solche, die nur regional herumsurfen, jedoch umso schlechter für solche, die es weltweit tun.
- Max-load: Derjenige, der am wenigsten Stau hat, wird zuerst durchgelassen. Dies führt dazu, dass bestimmte Verbindungen nie zustande kommen. Dies ist ein Bisschen das "Wer gute Verbindungen hat, der bringt's zu was".
Die Performance von TCP lässt sich folgendermassen beschreiben bzw. errechnen:
Sei S die Grösse eines Pakets
Sei W die Anzahl Pakete, die im Sende-Fenster Platz finden.
Sei O die Grösse der gesamten Datei.
Sei R die Bandbreite der Verbindung
Annahme: es treten keinerlei Fehler auf.
Wenn W*S/R grösser ist als RTT + S/R, so wird das erste ACK beim Sender ankommen, bevor das Sendefenster am Ende angelangt ist. Dadurch können alle Daten ohne Verzögerung sofort gesendet werden. Die gesamte Zeit, die es für die Übertragung der Datei inklusive Verbindungsaufbau braucht, ist somit 2*RTT + O/R. Wenn W*S/R kleiner ist als RTT + S/R, so muss der Sender nach jedem vollständigen Fenster ein bisschen warten. Dies ergibt eine Gesamtzeit von 2*RTT + O/R +(O/W*S)(S/R + RTT - W*S/R)