9.10. TCP – en pålitlig ström av byte

TCP, Transmission Control Protocol, är den andra tjänsten på transportlagret ovanpå IP. Där UDP bäst beskrivs som ”skicka ett paket och hoppas”, är TCP ”öppna en anslutning mellan två slutpunkter och behandla den som en tvåvägsrörledning av byte som den andra sidan definitivt får, i ordning och exakt en gång”. Det mesta av internettrafiken använder det, och det mesta av det kameran gör på nätverket använder det också.

9.10.1. Vad TCP lägger till utöver IP

TCP gör mycket mer än UDP. Det lägger till:

  • En anslutning. Innan någon data flödar utbyter de två slutpunkterna en kort handskakning för att komma överens om att de pratar med varandra. Anslutningen har ett tillstånd – ”öppen”, ”halvstängd”, ”stängd” – som båda sidor håller reda på.

  • Pålitlig leverans. Varje byte som avsändaren skickar in bekräftas av mottagaren. Allt som inte bekräftas inom en tidsgräns skickas igen. Applikationen ser aldrig en förlorad byte; den ser en fördröjning medan protokollet skickar om.

  • Leverans i ordning. Byte anländer i samma ordning som de skickades. Även om paket anländer till mottagaren i fel ordning, ordnar TCP om dem innan applikationen läser.

  • Flödeskontroll. Om mottagaren är långsam blir avsändaren tillsagd att sakta ner; anslutningen anpassar sig till den svagare partens hastighet.

  • Överbelastningskontroll. Om nätverket däremellan börjar tappa paket drar sig avsändaren tillbaka tills allt återhämtar sig. Detta hindrar någon enskild anslutning från att slå ut en mättad länk.

Allt detta sker automatiskt. Det Python-API som applikationen använder är helt enkelt send(bytes) och recv(n); TCP sköter allt annat under huven.

9.10.2. Handskakningen

En TCP-anslutning öppnas med ett trevägsutbyte innan någon data tillåts passera:

Ett diagram med två kolumner märkta "client" och "server". En pil från klienten till servern märkt "SYN", sedan en pil från servern till klienten märkt "SYN-ACK", sedan en pil från klienten till servern märkt "ACK". Under det en tjock pil märkt "data flowing both ways".

Trevägshandskakningen. När båda sidor har bekräftat är anslutningen öppen och data kan flöda.

Klienten skickar ett SYN-paket (synchronise) som ber om att öppna. Servern svarar med SYN-ACK (synchronise + acknowledge) och accepterar. Klienten skickar ett avslutande ACK för att bekräfta. Efter denna tur-och-retur är båda sidor överens om att anslutningen är öppen och har synkroniserat sina räknare för att hålla reda på vilka byte som har skickats och mottagits.

Handskakningen kostar en tur-och-retur-tid av latens innan den första användbara byten kommer fram. För lokala nätverk är det en millisekund; för anslutningar tvärs över kontinenter är det ungefär 100 ms. Detta är den huvudsakliga kostnaden för TCP och anledningen till att korta engångsmeddelanden ibland klarar sig bättre med UDP istället.

9.10.2.1. Den avslutande handskakningen

TCP-anslutningar stängs också med ett utbyte (ett FIN från varje sida). Endera änden kan stänga sin halva av anslutningen oberoende; ett halvstängt tillstånd där en sida har slutat skicka men den andra fortfarande pratar är tillåtet, om än ovanligt. Applikationen anropar normalt bara close() och låter protokollet sköta nedstängningssekvensen.

9.10.3. Vad TCP inte garanterar

Några saker som TCP ibland antas göra men inte gör:

  • Meddelandegränser. Applikationen skickar en ström av byte, inte en ström av meddelanden. Två send(b"hello")-anrop kan anlända som ett enda recv() av b"hellohello", eller som två recv()av varierande storlek. Om applikationen vill ha meddelanderamning måste den lägga till ramningen själv (en radbrytning, ett längdprefix, vad som helst). Att skicka JSON-dokument över TCP behöver till exempel att varje dokument separeras med en radbrytning eller någon annan markör.

  • Kryptering. TCP transporterar de byte applikationen gav det, i klartext, hela vägen. Om innehållet måste vara konfidentiellt måste applikationen kapsla in anslutningen i TLS (se Krypterade sockets och TLS).

  • Autentisering. TCP säkerställer att byten anlände intakta. Det säger ingenting om vem som skickade dem. Autentisering är också en angelägenhet för ett högre lager.

  • Aktivitet på en tyst anslutning. Om ingendera sidan skickar data under en lång tid är anslutningen tekniskt sett fortfarande öppen men kan inte upptäcka att den andra änden har kraschat eller försvunnit. Keepalive-sonder kan aktiveras på socketen för att åtgärda detta när det spelar roll.

9.10.4. När man ska använda TCP

TCP är rätt svar för nästan alla samtal som passar formen ”klienten öppnar en anslutning till en server, de utbyter några byte, anslutningen stängs när det är klart”. HTTP- och HTTPS-förfrågningar, SSH-sessioner, databasfrågor, filöverföringar, bilduppladdningar – allt över TCP.

Ta till UDP endast när samtalet inte passar den formen: oberoende självständiga meddelanden där förlust är acceptabel, multicasttrafik, tidssynkronisering, namnuppslagningar, eller extremt latenskänsliga fall där handskakningens kostnad är oöverkomlig.

Med portar, UDP och TCP alla på bordet är berättelsen om transportlagret klar. Python-API:t som exponerar båda finns på nästa sida: Socket-objekt.