Telekommunikációs hálózatok > Előadás anyag > Szállitói réteg
Csak a végpontok implementálják. Feladata adatfolyamok (de)multiplexálása, esetleg garantálhatja az adatok intergritását (TCP), de ez nem mindig kell (UDP), esetleg biztosíthat hosszú élettartamú kapcsolatokat, sorrendhelyes átvitelt, hibadetektálást, folyam és torlódás vezérlést.
Ha beérkezik egy csomag, melyik folyamatoknak (process) kell szállítani. Az IP fejlécben nincs erre vonatkozó információ, ezért portokat használunk a folyamatok beazonosítására. Egy szerver több klienssel kommunikálhat, ekkor ugyanazt a portot használják. A végpontok azonosítása így történik: <forrás ip, forrás port, cél ip, cél port, protokoll (TCP/UDP)>.
Saját fejlécet (8 bájt) rak a csomagba. Ebben a fejlécben van a forrásport, célport, adathossz és kontrollösszeg, amely a hibadetektáláshoz kell.
Vannak protokollok, amelyek UDP felett valósíthatók meg. Ilyen protokollokat használnak a valós idejű alkalmazásokban, videóknál, hívásoknál stb.
A TCP kapcsolat alapú (előbb kiépítjük a kapcsolatot, csakis utána tudunk küldeni), bájtcsatorna alapú, sorrendhelyes, a bájtokat hibamentesen szeretné átvinni. Folyam vezérlés (gyors adó ne terhelje túl a lassú vevőt), torlódás vezérlés, fair viselkedés jellemzi.
A TCP fejléc 20 bájtos. Továbbá kiegészülhet opcionális fejlécekkel, ami összesen 4 bájtnyi lehet.
Azért kell kiépíteni a kapcsolatot, hogy kicseréljék a kezdeti állapotokat. A legfontosabb a két sorszám (a sorszámok véletlenszerű értékre inicializálódnak biztonsági okokból).
TCP Flagek:
A kliens küld SYN flages csomagot a saját sorszámával és 0-val, erre a szerver
SYN/ACK-val válaszol a
saját sorszámával és a kliens sorszámánál eggyel nagyobbal, erre a kliens küld egy ACK nyugtát a
sajátjánál eggyel nagyobb sorszámmal (ezt kapta a szervertől az előbb) és a szerver sorszámánál
eggyel
nagyobb sorszámmal (ebben már lehet adat is a szervernek). Azért egyel nagyobbat küldenek, mert a
nyugta mindig a következő elvárt sorszámot tartalmazza.
A SYN/ACK üzenet kliensoldali megérkezésénél a kliensnél már él a kapcsolat, az ACK szerveroldali
megérkezésénél a szervernél is él a kapcsolat.
Forrás hamisítás:
Ha valaki megtudja a sorszámunkat, akkor beékelődhet közénk és a szerver közé, ezért kell randomnak választani a kezdeti sorszámot.
SYN flood:
A kapcsolat állapotait a szerver kezeli. Amikor egy új hoszt csatlakozik, akkor a SYN állapot memóriát foglal a szerveren. Ezt használják ki a SYN flood támadások, amikor újabb és újabb SYN üzeneteket küld a kliens és ezzel elárasztja a szervert.
Erre megoldás a SYN cookie. Itt nem foglalódik erőforrás. A SYN-ből kapott sequence numberből számolunk egy cookiet valamilyen speciális algoritmussal, ezt kódoljuk bele a szerver sequence numberébe a SYN/ACK-ba és küldjük vissza a kliensnek, majd ha az ACK is megjött, csak akkor foglalunk le erőforrást.
Kiépüléskor erőforrás foglalódik a szerveren, ezért ezt a kapcsolat bontásánál fel is kell szabadítani. Bármelyik fél kezdeményezheti a kapcsolat bontását. Ha a kliens kezdeményezi, akkor egy FIN üzenetet küld. A szerver küld erre egy ACK-t az egyel nagyobb sorszámmal. Ekkor a kliens lezártja a kapcsolatot, de a szerver még nem biztos. Ilyenkor még előfordulhat, hogy a szerver még küld adatot. Erre válaszol a kliens, de itt már nem kapja meg program az üzenetet, hanem a kliens operációs rendszere válaszol. Miután mindent elküldött a szerver is, küld egy FIN-t és ezzel ő is lezártnak tekinti a kapcsolatot. Erre még a kliens operációs rendszere küld egy ACK-t. Ekkor zárult csak le teljesen a kapcsolat.
Kezdetben random értékek, amelyek a folyam bájtjait számozzák és nem a csomagokat. Ez egy 32 bites érték, ami ciklikusan megy körbe és körbe.
A bájtfolyamot szegmensekre bontjuk, aminek a maximum méretét a maximum szegmensméret (Maximum Segment Size (MSS)) határozza meg. Ez nem független az MTU-tól, a cél az, hogy olyan MSS legyen, hogy itt már ne történjen fragmentáció.
Mindkét fél küldhet és fogadhat adatot irányonként különböző sorszámokkal. Sőt a nyugtát belerakhatjuk abba a csomagba, amivel adatot küldünk.
Nem szeretnénk túlterhelni a fogadót. Erre a megoldás a csúszóablak lesz (ilyen volt adatkapcsolati rétegben is).
A fogadó elküldi a küldőnek a puffer méretét, ez a meghirdetett ablak (advertised window). Minden ACK után léptetjük a csúszóablakot, ezt a két fél folyamatosan, minden szegmenssel csinálja, mivel van egy vételi és egy küldési ablak is. Az ablak akár nulla is lehet, így megtiltjuk a másik oldalnak a küldést.
Körülfordulási idő (round trip time (RTT)):
A körülfordulási idő sokkal nagyobb lehet, mivel az egész interneten is át kell mennie egy csomagnak oda-vissza. Ha ez kicsi, akkor a csúszóablak gyorsan léptethető, ha nagy, akkor lassan jönnek a nyugták és lassan "csúszik". A TCP átvitele arányos a kiküldési ablakméret / RTT-vel.
Kicsi maximum szegmensméretnél sok helyet foglalnak a fejlécek a hasznos adathoz képest. Ez nem hatékony. A TCP próbál minél nagyobb szegmens méretekkel dolgozni. Ha lehet, akkor pontosan ennyi bájtot küldjünk, amennyi maximális szegmensméret, (ha többet is kellene már küldeni, akkor azonnal küldünk). Ha nem lehet, akkor várunk, amíg nem nyugtázódik mindenki, és közben lehet, hogy lesz több bájt, amit lehet majd küldeni, ez ugye késlelteti a küldést. Viszont ha sokáig nem jön még semmi, akkor kiküldhetjük a kicsi adatot is. Ezt ki lehet kapcsolni (TCP_NODELAY).
Az IP és a TCP is kontrollösszegből számolja ki a hibát. Sorszámok segítenek a sorrendhelyes átvitelben. A küldő oldalon detektálhatjuk az elveszett szegmenseket, időtúllépéssel (Retransmission Time Out (RTO)). Ha bizonyos ideig nem érkezik nyugta, akkor az egy elveszett szegmens. Ehhez a két végpont távolságát és az RTT-t kell becsülni.
Időtúllépés (Retransmission Time Out (RTO)):
Nem lehet túl kicsi a timeout, mert folyamatosan újra küldené a csomagokat. Az RTO-t RTT becsléssel lehet belőni. Ennek érdekében az elején elküldünk egy adatot, amire kapunk egy nyugtát, majd ezekből az időkből mozgóátlaggal becslünk új RTT-t.
új RTT = alpha * (régi RTT) + (1-alpha) * (új küldés és nyugta ideje)
RTO = 2 * (új, becsült RTT)
Azokat a mintákat nem nézzük, ami csomag újra küldéséből jött, mert alapból lehet hogy az újra küldés után kapásból megjön a nyugta, mivel azt az előzőre kaptuk még. Ilyenkor kicsi lenne az új RTT, de ezt ez az algoritmus megoldja.
Akkor van torlódás, ha a terhelés nagyobb, mint a kapacitás a hálózaton. Ekkor a végpont-végpont késleltetés megnő, a várakozási sorok megtelítődnek és csomagvesztést okoz. A RED algoritmus már a betelítődés előtt eldob csomagokat az átlag alapján. A kapacitás nem egyenletes a hálózaton, mert más is használja a hálózatot és sokan versengenek a sávszélességért. Ilyenkor megnövekszik a késleltetés és sávszélesség pazarlás is történik az újra küldések miatt.
Megnövekedett terhelés:
Könyök (knee) pont: ideális pont, itt közel vagyunk a maximális
átvitelhez, amit el
lehet érni, de a késleltetés még alacsony
Szírt (cliff) pont: innen fog túlterhelődni a rendszer, ahonnan már csomagvesztések
lesznek, a késleltetés végtelen lesz
Próbálunk a könyök ponton maradni. A meghirdetett ablak (advertised window) nem oldja meg a problémát, mivel őt csak az érdekli, hogy a fogadót ne terheljük túl, az viszont már nem, hogy a hálózat ne omoljon össze. Megoldások:
Torlódásvezérlés:
Megpróbálunk a szírt bal oldalán maradni. Minden TCP kapcsolatnak van ablaka (nem-nyugtázott csomagoknak), de most bevezetünk egy torlódási ablakot is (congestion window (cwnd)), ezt a torlódás vezérlés fogja kontrollálni. A torlódás detektálása küldő-oldai probléma, itt próbáljuk meg kitalálni a hálózat állapotát (csomagvesztés, nyugta hiány vagy nyugta duplikátum alapján).
Nyugta fogadás esetén növeljük a cwnd-t az RTT-vel arányosan (ha nem tapasztaltunk problémát, valószínű, hogy küldhetünk gyorsabban is), csomagvesztés esetén pedig csökkentjük (mivel akkor valahol torlódás van). A küldési ablak mindig a kisebb lesz a torlódási ablak és a meghirdetett ablak közül (wnd = min (cwnd, adv_wnd)). Ennek két fázisa van: lassú indulás (slow start), torlódás elkerülése ().
A lassú indulásnál (slow start) a cél, hogy gyorsan elérjük a könyökpontot. A TCP óvatosan indul el, a torlódási ablakot egy pár szegmens méretre állítja és onnan növeli a könyökpontig exponenciálisan.
A torlódás elkerülésénél a lényeg, hogy a könyök pont után már nagyon óvatosan szabad növelni a torlódási ablakot, hogy ne érjük el a szírt pontot cwnd >= ssthresh. (ssthresh: vágási érték, amit a cwnd frissítésére használunk.)
Additive Increase Multiplicative Decrease (AIMD):
A növekedés inkrementális, a csökkenés multiplikatív lesz a küszöb érték belövésénél. Kezdetben a torlódási ablak (cwnd) = 1 (mivel nem ismerjük a hálózat állapotát). Minden egyes nyugtával eggyel szegmenssel növeljük a torlódási ablak méretét, amíg el nem érjük ssthresht és csomagvesztés sem történik ssthresh = adv_wnd. A lassú indulás nem lassú, mivel a cwnd exponenciálisan nő, mert a nyugták nem egyenletesen érkeznek vissza. Kezdetben a ssthresh küszöbérték nagyon magas. Vagy eddig az ssthresh-ig növeljük a cwnd-t vagy addig, amíg csomagvesztés nem történik. Ekkor viszont az ssthresh értékét a torlódási ablak felére állítjuk, innen kezdődhet elölről a slow start vagy valami más történik (TCP torlódás vezérlés függő)).
Torlódás elkerülés:
Azt hisszük, hogy ssthresh az az érték, ami közel visz a könyökponthoz és ezt ugye már el is értük (mivel nem volt csomagvesztés). A küszöb (ssthresh) után viszont már nem akarunk elérni a szírt pontig. Ide ugye akkor lépünk, amikor a torlódási ablak a küszöbérték felett van. Additive Increase Multiplicative Decrease (AIMD): itt már nem eggyel, hanem 1 / cwnd-vel növeljük a torlódási ablakot, azaz cwnd szegmens küldése után növelünk csak eggyel (tehát amikor minden szegmens nyugtázva lett) pl 10 szegmenst küldünk ki (mert ennyi a cwnd), majd ha mind a 10-nek megkapjuk a nyugtáját, akkor növeljük csak cwnd-t eggyel. Lineáris növekedés van a slow starttal ellentétben, ami gyorsan el szeretné érni a könyökpontot, de ez után még lehet kapacitás a rendszerben. A lineáris itt azért jobb, mert óvatosak vagyunk és nem szeretnénk túlterhelni a rendszert.
TCP Tahoe:
Ez az eredeti TCP torlódás elkerülő algoritmusa. A slow start itt is megvolt, hogy elérjük a könyökpontot hamar. A küszöbértéket a meghirdetett ablakra állították. Majd a csomagvesztési szinten használt torlódási ablak felére állítjuk a küszöbértéket és visszamegyünk slow startba, majd jön az AIMD (itt megint a felére állítjuk a küszöbértéket és a slow starttal kezdődik minden elölről). Emiatt fluktuálni fog a cwnd és kihasználatlan marad a hálózat.
TCP Reno:
Majd jött a TCP Reno = TCP Tahoe + gyors újraküldési mechanizmus. Itt két részre bontjuk a torlódást: időkorlát túllépésre, amikor nem jön nyugta és 3 duplikált nyugtára, amikor 1 szegmens elveszett, de 3 átment, amik miatt kaptuk a 3 nyugtát. Itt nem megyünk vissza slow startba, hanem lefelezzük a torlódási ablakot és erre az új értékre állítjuk be a küszöbértéket is, ezzel kihagyva a slow start fázist és az AIMD-re ugorva. Ha időtúllépés történik, akkor visszamegyünk a slow start fázisba. Így a cwnd szűkebb spektrumon fog fluktuálni.
TCP NewReno:
A probléma az volt, hogy egy rossz sorrend is ki tudott váltani újra küldéseket a Renonál. Ez egy javítása a Renonak. Nem kell 3 duplikált nyugta, mindegyik duplikált nyugta esetén újra küldést vált ki. Ezzel a probléma esélye kicsi volt.
Vegas:
Késleltetés alapon kerüli el a torlódást. Felteszi, hogy a csomagvesztés még nem feltétlenül jelent túlterhelést, inkább a késleltetést nézi. Vezeték nélküli küldésekhez lett kifejlesztve. Ez az interneten nem jó, mert fluktuálhat a késleltetés a nagy pufferek miatt.
Compound TCP (Windows):
Késleltetés és vesztés (mint a Renonál) alapú torlódási ablakot tart számon. Összetett torlódás vezérlés. A torlódási ablakot két különálló ablakra osztja, hagyományos vesztés alapú és új, késleltetés alapúra. A késleltetés alapú, mint egy gyorsítási/lassítási faktor, alacsony késleltetésnél növeljük, magasnál csökkentjük. Agresszívan reagál a késleltetés változására (RTT).
TCP Cubic (Linux, Windows 10+):
Olyan, mint a Reno, csak AIMD helyett egy köbös függvényt használ. A gyorsabb a felfutása, mint a slow start. A felfutás pontosan egyszer, legelőször, használja csak. Utána óvatosan közelítjük meg az előző torlódási szintet, itt ellenőrizzük, hogy fennáll-e még a torlódás, ha nem, akkor meg jön a tesztelési fázis, hogy mi a mostani kapacitás.
Hogy ne legyen tényleges torlódás a hálózaton (a FIFO sorok ne teljenek be), ezért ezt megelőzhetjük úgy, hogy random csomagokat dobálunk el, amikor még van hely a sorban, ezzel jelzünk a küldőnek, hogy vegyen vissza, mert kezdünk túlterhelődni. Nyilvántartjuk az átlagos sorhosszt, bevezetünk egy minimális és maximális értéket is, ha sor hossza kisebb, mint a minimális, akkor továbbítunk, ha nagyobb, de még nem érte le a maximálisat, akkor random eldobunk csomagokat, ha a maximális fölött van, akkor minden eldobunk, ami bejön.
A csomagot nem feltétlenül dobjuk el. Lehet ECN flaget alkalmazni. Az ECN flag megspórolja az újra küldést úgy, hogy beállítja az ECN biteket ezzel jelezve a küldőnek, hogy vegyen vissza. Ma már nem nagyon használnak ECN-t.
A hálózat felépítése más, nagyobbak a linkek, kisebbek a várakozási sorok, a topológia is többszörösen bekötött fa.
A DCTCP-t az adatközpontokra találták ki. Ez használja az ECN-t a routerekben, de ez a TCP nem csomagvesztésként tekint az ECN-re, hanem nyilvántartja, hogy 10 csomagból mennyi volt ECN-nel megjelölve és arányosan változtat a torlódási ablakon.