9.10. TCP – megbízható bájtfolyam¶
A TCP, vagyis a Transmission Control Protocol, a másik szállítási rétegbeli szolgáltatás az IP tetején. Míg a UDP-t leginkább úgy lehet jellemezni, hogy „küldj egy csomagot és reménykedj”, addig a TCP azt jelenti, hogy „nyiss egy kapcsolatot két végpont között, és kezeld kétirányú bájtcsőként, amelyet a másik fél biztosan megkap, sorrendben és pontosan egyszer”. Az internetes forgalom nagy része ezt használja, és a kamera hálózati tevékenységének nagy része is.
9.10.1. Mit ad a TCP az IP-hez¶
A TCP sokkal többet tesz, mint a UDP. A következőket adja hozzá:
Kapcsolat. Mielőtt bármilyen adat áramlana, a két végpont egy rövid kézfogást folytat, hogy megállapodjanak abban, hogy beszélgetnek. A kapcsolatnak van állapota – „nyitott”, „félig zárt”, „zárt” –, amelyet mindkét oldal nyomon követ.
Megbízható kézbesítés. Minden bájtot, amelyet a küldő betesz, a fogadó nyugtáz. Bármit, amit egy időkorláton belül nem nyugtáznak, újraküldenek. Az alkalmazás soha nem lát elveszett bájtot; csak egy késleltetést tapasztal, miközben a protokoll újraküldi.
Sorrendhelyes kézbesítés. A bájtok ugyanabban a sorrendben érkeznek meg, amelyben elküldték őket. Még ha a csomagok rossz sorrendben is érkeznek a fogadóhoz, a TCP átrendezi őket, mielőtt az alkalmazás olvasná őket.
Áramlásszabályozás. Ha a fogadó lassú, a küldőt felszólítják a lassításra; a kapcsolat alkalmazkodik a gyengébb végpont sebességéhez.
Torlódásszabályozás. Ha a köztes hálózat csomagokat kezd eldobni, a küldő visszafogja magát, amíg a helyzet helyre nem áll. Ez megakadályozza, hogy egyetlen kapcsolat tönkretegyen egy telített kapcsolatot.
Mindez automatikus. A Python API, amelyet az alkalmazás használ, egyszerűen send(bytes) és recv(n); minden mást a TCP kezel a háttérben.
9.10.2. A kézfogás¶
Egy TCP-kapcsolat egy háromlépéses cserével nyílik meg, mielőtt bármilyen adat átjuthatna:
A háromlépéses kézfogás. Miután mindkét oldal nyugtázott, a kapcsolat nyitva van, és az adatok áramolhatnak.¶
A kliens küld egy SYN (szinkronizálás) csomagot, kérve a megnyitást. A szerver egy SYN-ACK (szinkronizálás + nyugtázás) csomaggal válaszol, elfogadva azt. A kliens egy záró ACK csomagot küld a megerősítéshez. E körútidő után mindkét oldal egyetért abban, hogy a kapcsolat nyitva van, és szinkronizálták számlálóikat annak nyomon követésére, hogy mely bájtokat küldték el és fogadták.
A kézfogás egy körútidőnyi késleltetésbe kerül, mielőtt az első hasznos bájt átjutna. Helyi hálózatok esetén ez egy ezredmásodperc; kontinensek közötti kapcsolatok esetén ez nagyjából 100 ms. Ez a TCP fő költsége, és ez az oka annak, hogy a rövid, egyszeri üzeneteknek néha jobb inkább a UDP-t használniuk.
9.10.2.1. A záró kézfogás¶
A TCP-kapcsolatok szintén egy cserével záródnak (mindkét oldalról egy-egy FIN). Bármelyik végpont függetlenül lezárhatja a kapcsolat saját felét; egy félig zárt állapot, amelyben az egyik oldal befejezte a küldést, de a másik még beszél, jogszerű, bár ritka. Az alkalmazás általában csak a close() hívást használja, és hagyja, hogy a protokoll kezelje a leállítási folyamatot.
9.10.3. Mit nem garantál a TCP¶
Néhány dolog, amit a TCP-ről néha feltételeznek, de nem tesz meg:
Üzenethatárok. Az alkalmazás egy bájtfolyamot küld, nem üzenetek folyamát. Két
send(b"hello")hívás megérkezhet egyetlenrecv()híváskéntb"hellohello"formában, vagy két, eltérő méretűrecv()hívásként. Ha az alkalmazás üzenetkeretezést szeretne, magának kell hozzáadnia a keretezést (egy sortörést, egy hosszelőtagot, bármit). JSON-dokumentumok TCP-n keresztüli küldéséhez például minden dokumentumot sortöréssel vagy más jelölővel kell elválasztani.Titkosítás. A TCP a bájtokat, amelyeket az alkalmazás adott neki, nyíltan, a teljes úton végigviszi. Ha a tartalomnak bizalmasnak kell lennie, az alkalmazásnak TLS-be kell csomagolnia a kapcsolatot (lásd Titkosított socketek és TLS).
Hitelesítés. A TCP gondoskodik arról, hogy a bájtok sértetlenül érkezzenek meg. Arról semmit nem mond, hogy ki küldte őket. A hitelesítés szintén magasabb rétegbeli kérdés.
Életjelek egy csendes kapcsolaton. Ha egyik oldal sem küld adatot hosszú ideig, a kapcsolat technikailag még nyitva van, de nem képes észlelni, hogy a másik végpont összeomlott vagy eltűnt. A keepalive próbák engedélyezhetők a socketen, hogy ezt orvosolják, amikor számít.
9.10.4. Mikor használjuk a TCP-t¶
A TCP a helyes válasz szinte minden olyan beszélgetésre, amely beleillik a következő mintába: „a kliens kapcsolatot nyit egy szerverhez, kicserélnek néhány bájtot, a kapcsolat lezárul, amikor készen vannak”. HTTP- és HTTPS-kérések, SSH-munkamenetek, adatbázis-lekérdezések, fájlátvitelek, képfeltöltések – mind TCP-n keresztül.
Csak akkor nyúlj a UDP-hez, ha a beszélgetés nem illik ebbe a mintába: független, önálló üzenetek, ahol a veszteség elfogadható, multicast-forgalom, időszinkronizálás, névfeloldások, vagy szélsőségesen késleltetésérzékeny esetek, ahol a kézfogás költsége megengedhetetlen.
A portokkal, a UDP-vel és a TCP-vel együtt a szállítási réteg története teljes. A Python API, amely mindkettőt elérhetővé teszi, a következő oldalon található: Socket objektumok.