TCP ist ein verbindungsorientiertes Übertragungsprotokoll und die Grundlage fast aller Dienste im Internet. Wer versteht, wie der Verbindungsaufbau funktioniert, kann Netzwerkprobleme deutlich schneller eingrenzen.
Der Aufbau: Drei Nachrichten
Client Server
| --- SYN (seq=x) --------------------> | "ich moechte verbinden"
| <-- SYN-ACK (seq=y, ack=x+1) -------- | "einverstanden"
| --- ACK (ack=y+1) ------------------> | "bestaetigt"
| |
| ========== Datenfluss =============== |
Das ist der "Three-Way Handshake". Jede der drei Nachrichten
hat eine Aufgabe:
SYN Client nennt eine Startnummer (seq) fuer seine Bytes
SYN-ACK Server nennt die eigene Startnummer und bestaetigt
ACK Client bestaetigt die Startnummer des Servers
Erst danach fliessen Nutzdaten. Das kostet eine Verzoegerung
(Round-Trip) - der Grund, warum HTTP/3 (QUIC) diesen Schritt
mit dem Verbindungsaufbau von TLS zusammenlegt.
Der Abbau: Vier Nachrichten
| --- FIN --------------------------> | "ich habe nichts mehr"
| <-- ACK --------------------------- | "verstanden"
| <-- FIN --------------------------- | "ich auch nicht mehr"
| --- ACK --------------------------> | "verstanden"
| |
Zustaende, die man im Werkzeug "ss" sieht:
LISTEN wartet auf Verbindungen
SYN-SENT Client hat SYN geschickt, wartet auf SYN-ACK
SYN-RECEIVED Server hat SYN-ACK geschickt
ESTABLISHED Verbindung steht
FIN-WAIT-1/2 eigene Seite hat geschlossen
CLOSE-WAIT Gegenstelle hat geschlossen, Anwendung noch nicht
TIME-WAIT Wartezeit nach dem Schliessen (2 x MSL, meist 60s)
LAST-ACK wartet auf die letzte Bestaetigung
TIME-WAIT ist wichtig: Es verhindert, dass verspaetete Pakete
einer alten Verbindung in eine neue mit gleicher Nummer geraten.
Viele TIME-WAIT-Zustaende auf einem Server sind daher normal -
solange es nicht zehntausende sind.
Verbindungen ansehen
# LISTENDE Sockets mit Prozess
ss -tlnp
# ALLE TCP-Verbindungen mit Prozess
ss -tanp | head -40
# Nur bestehende Verbindungen
ss -tn state established
# Anzahl je Zustand - der schnellste Ueberblick bei Last
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# Wer verbindet sich oft mit Port 443?
ss -tn dst :443 | awk 'NR>1 {print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
# Netzwerkstatistik seit dem Start
ss -s
nstat -az | grep -E 'TcpRetrans|TcpExtTCPAbortOn|TcpOutSegs|TcpAttemptFails'
# Das wichtigste Leistungsmass: Wiederholungen
# TcpRetransSegs / TcpOutSegs -> sollte unter 0,5 % liegen
awk '/TcpRetransSegs|TcpOutSegs/ {print $1, $2}' /proc/net/snmp
# Zeitgeber des Kernels
sysctl net.ipv4.tcp_keepalive_time # 7200 s - recht lang
sysctl net.ipv4.tcp_fin_timeout # 60 s
sysctl net.ipv4.tcp_tw_reuse # TIME-WAIT wiederverwenden
# Fehlersuche: Wer lauscht auf einem Port?
ss -tlnp 'sport = :8080'
lsof -i :8080
fuser -n tcp 8080
Warum das bei der Fehlersuche hilft
"Verbindung wird abgelehnt" (Connection refused)
-> SYN erreicht den Server, aber es lauscht nichts.
-> Kein Paketfilter-Problem: die Anwendung laeuft nicht
oder lauscht auf einer anderen Adresse.
-> ss -tlnp zeigt, worauf sie lauscht (0.0.0.0 oder 127.0.0.1!)
"Verbindung laeuft in die Zeitueberschreitung" (timeout)
-> SYN wird verworfen. Typisch: Paketfilter, Firewall,
falsche Route, falscher Port in der Weiterleitung.
-> Von aussen pruefen: tcpdump auf dem Server
(kommen die SYN-Pakete ueberhaupt an?)
"Verbindung bricht nach 60 Sekunden zusammen"
-> Mittendrin keine Pakete mehr: NAT-Tabelle abgelaufen
(TCP-Zeitueberschreitung) oder ein Paketfilter mit
Zustandsverfolgung hat den Eintrag verloren.
"Verbindung bleibt bei TLS stehen"
-> TCP funktioniert, aber der Handshake scheitert:
Zertifikat, Protokollversion, Zwischenstelle (Proxy)
oder ein falscher Aufrufname (SNI).
"Manche Verbindungen klappen, andere nicht"
-> Lastverteilung: eine von mehreren Gegenstellen ist
defekt oder hat ein anderes Zertifikat. Von Hand
jede Adresse einzeln ansprechen.
"Zeitueberschreitung nur bei grossen Uebertragungen"
-> MSS/MTU-Problem: Fragmente werden unterwegs verworfen.
Test: ping -M do -s 1472 (1472+28 = 1500)
Sockets und Verbindungen unter Linux
# Verbindungsanfragen in der Warteschlange (Backlog)
ss -tln | awk 'NR>1 {print $2, $3, $4, $5}'
# Recv-Q bei LISTEN = wartende Verbindungen
# Send-Q bei LISTEN = Backlog-Grenze
# Ist Recv-Q dauerhaft hoch -> Anwendung nimmt zu langsam an
# Verbindungswarteschlange des Kernels
sysctl net.core.somaxconn # 4096 ist ein guter Wert
sysctl net.ipv4.tcp_max_syn_backlog
# "SYNs to LISTEN sockets dropped" steigend -> Backlog zu klein
# Ports in Benutzung
ss -tln | wc -l
ss -tan | wc -l
# Zeitueberwachung: TCP-Verbindungen, die nie fertig werden
sysctl net.ipv4.tcp_syn_retries # 6 (etwa 127 s)
sysctl net.ipv4.tcp_synack_retries
# Wichtig fuer Server hinter Lastverteilern: Die echte Quelle
# TCP kennt keine Weiterleitungs-Kopfzeilen. Adressen
# kommen ueber X-Forwarded-For (HTTP) oder PROXY protocol
# (TCP). Ohne das sieht die Anwendung nur den Lastverteiler.
Prüfliste
- Kennst du den Unterschied zwischen Connection refused und Timeout – und was er jeweils bedeutet?
- Ist auf dem Server geprüft, ob die Anwendung auf
0.0.0.0oder nur auf127.0.0.1lauscht? - Ist die Wiederholungsrate des Netzes im Blick (Zielwert unter 0,5 %)?
- Ist
somaxconnfür stark belastete Dienste angepasst? - Sind die Zeitlimits von Lastverteiler und Anwendung aufeinander abgestimmt (kein 30-s-Proxy vor einer 120-s-Abfrage)?
- Ist die Weiterleitung der echten Client-Adresse gesetzt?
- Ist die MTU auf dem gesamten Pfad einheitlich?
Häufige Fehler
- Anwendung lauscht nur lokal. Der Klassiker:
ss -tlnpzeigt127.0.0.1:8080, von außen kommt nichts an. Die Anwendung muss auf0.0.0.0lauschen. - Firewall-Regel vergessen. Der Dienst läuft, aber Pakete werden verworfen. Timeout statt Fehlermeldung.
- Zu langes
tcp_keepalive_time. Zwei Stunden sind für viele Anwendungen zu lang. Lastverteiler und Firewalls werfen die Verbindung vorher aus ihrer Tabelle – der Client merkt es erst beim nächsten Schreibversuch. - Ports doppelt belegt. Zwei Prozesse auf demselben Port: Der zweite startet nicht.
SO_REUSEPORTglaubt zu „funktionieren“, verteilt aber zufällig. - Verbindungsabbruch nach einer Minute. Meist eine NAT-Tabelle, die abschaltet. Mit Keepalive-Paketen in kürzeren Abständen oder
tcp_keepalive_timekleiner als die NAT-Zeitüberschreitung lösen. - MSS-Klemmen (MSS clamping) fehlt. Bei einer VPN- oder Tunnelstrecke werden große Pakete verworfen, kleine gehen durch. Von außen sichtbar als „Seite lädt, aber Bilder fehlen“.
Verwandte Grundlagen: UDP, IP-Adresse, tcpdump, ss und netstat.