Erlang orosz mintegy TCP socket for Dummies

A TCP socket for Dummies

Egy nagyon leegyszerűsített történet a TCP socket azok számára, akik nem a téma :)

Ültem és írtam belső dokumentáció a projekt. És ez azért volt szükség, többek között leírja a végrehajtás egy foglalat a kliens oldalon. Magam ezt tette végrehajtás Java-ban egy adott ügyfél, végezze funkcionális és stressz teszt szerver. Szükség van egy másik megvalósítása a .NET alkalmazások Unity, és hogy lesz egy igazi ügyfél az én szerver. És ez a felismerés akkor írj egy másik fejlesztő.

Így írtam a Java aljzat, és rájött, hogy jó lenne elmondani először, hogyan működik a TCP socket. És rájöttem, hogy ez a történet lehet lefektetett a nyilvánosság előtt, mert ez nem egy konkrét belső dokumentumokat. Nos, ez terjedt :)

Hogyan működik az aljzat alacsony szinten? Beszélünk TCP Full Duplex socket nélkül kiegészítőket, mint a HTTP. Full Duplex - a két csövet. Az egyik cső az adatok áramlását a klienstől a szerverhez. Szerint a másik cső áramlást a szerver a kliens. Ezek áramlási kis csomagokban, mint például a 1500 byte (attól függően, hogy a hálózati konfiguráció).

Csövek működnek egymástól függetlenül. Mi folyik keresztül, nem akadályozza meg, hogy átfolyik a másik.

És vele dolgozni, meg kell oldani a két problémát.

A probléma kitermelése adatokat az aljzat

Itt egy ügyfél küld a szervernek, egyetlen adat. Ez mind elfér egy csomagban. És ez nem illik, lehet osztani több csomagot. TCP garantálja, hogy ezek a csomagok elérni, és eléri a megfelelő sorrendben. De a kiszolgáló valahogy tudnia kell, hogyan ezek a csomagok újra gyűjteni szilárd adatot.

Nézzük önkényesen elképzelni, hogy a kliens küld egy kérést:

Jelenleg nem érint a téma a sorszámozás adatokat azok továbbítható semmilyen formában. Tegyük fel, hogy egy tárgy, például ahogy az a nyelv a programozás, ahol írunk az ügyfél része. És ez a cél valahogy szerializálódnak egy byte tömböt. Például szerializált formában, így fog kinézni:

Tegyük fel, hogy egy nagy tárgyat és egy byte tömböt, hogy minél több. Az egyik csomag, ő nem kapott, megosztott volt, és folytatta a cső formájában 3 csomag:

Következésképpen, a szerver kiolvassa az első darab cső. És ő vele csinálni? Meg lehet próbálni, hogy deserialize. Ha hibaüzenetet kap, akkor egyértelmű, hogy az adatok nem teljes, és meg kell, hogy minél több. És így minden alkalommal valami jön ki a csőből, megpróbáljuk deserialize azt. Kiderült - jól értelmezi, és küldje el további feldolgozásra. Ez nem működik - további adatokra vár.

De aztán a rossz dolog az, hogy az extra kísérletek deserialize létre fog hozni egy extra terhet a CPU. Kell még egy lehetőséget.

Az Erlang gen_tcp modul különböző lehetőségeket kínál a probléma megoldására. Nézzük használni, amit már ott van. Például, van egy kiviteli alak, amelyben a kiszolgáló feltételezi, hogy minden egyes ügyfél egy kérés fejlécében. És a cím hosszát tartalmazza az adatok teszik ki a kérést.

Azaz, egy lekérdezés a következőképpen néz ki:

És osztva csomagokat, mint ez:

Ha a szerver jön a szerver 42 olvasható a cím, látja, mint a lekérdezés hossza - 42 bájt, és megérti, hogy meg kell várni, amíg jönnek, ezek a 42 bájt. És akkor deserialize adatokat és értelmezze. Például az értelmezés lehet, hogy a szerver kéri a bejelentkezési eljárás érveket „Bob” és „123”. Hasonlóképpen, akkor is kivonják az adatokat és az ügyfél mikor lesz a szerverről.

fejléc mérete lehet 1 vagy 2, vagy 4 bájt. Az ilyen változatok kínál gen_tcp. Ha a használt aktív üzemmódban. (És egy passzív módban, mi kivonat és értelmezni ezt a fejlécet, így tedd, amit akarsz).

Mi a mérete a fejléc jobb? 1 byte-ban illeszkedjen a számát 2 ^ 8 = 256. Ekkor a kérést nem lehet nagyobb, mint 256 bájt. Ez túl kevés. A 2 bájt illeszkedjen száma 2 ^ 16 = 65536. Ennélfogva egy kérelmet lehet 65,536 bájt. Ez elegendő a legtöbb esetben.

De például, akkor lehet, hogy elküldi a szervernek nagy lekérdezések, úgyhogy 2 bájt a cím nem lesz elég. Itt szükség van rá, és vettem egy fejléc 4 byte.

Vegyünk valami vette, de én fulladás varangy :) Az ilyen kéréseket is valamivel nagyobb. Alapvetően valamennyi kérelmet kicsi, de mindegy akkor használja a 4 bájtos fejlécet. Van kizáró optimalizálás. Például használhatja a két cím. Először is, egy byte-os, jelzi a hossza a második. Egy második, 1-4 byte jelzi a csomag hossza :) Vagy lehet használni dimenzió int, elfoglalja byte 1-4, ahogy történik AMF szerializációnak. mentheti sávszélességet, ha szükséges.

Természetesen az ilyen kicsinyes optimalizálás csak nevetni azoknak a HTTP :) HTTP nem egy kicsit, és minden elküldött kérés beteges csomag metaadatok, ez nem a megfelelő szerver, és mivel a pazarlást a forgalom a skála nem hasonlítható az én ügyes TCP socket :)

A probléma a megfelelő kérelmek és válaszok

Itt az ügyfél a kérést, és egy kicsit később a másik cső rá valami közbejött. Mi a válasz az utolsó lekérdezés? Vagy válasz, hogy néhány korábbi lekérdezést? Vagy nincs válasz, és az aktív nyomja információk kezdeményezésére a szerver? Az ügyfél kell valahogy tudni, hogy mit kell tennie.

Egy jó lehetőség - minden ügyfél kérésére kell egy egyedi azonosítót. Válasz a szerver az azonosítóval. Annak érdekében, hogy meg tudja határozni, amely a kérelem érkezett a válasz.

Általában szükség van a három változatban a kliens-szerver kölcsönhatás:

  • A kliens küld egy kérést a szerver, és azt szeretnék, hogy a választ
  • A kliens küld egy kérést a szerver, és nem kell semmilyen választ
  • A szerver aktívan tolja adatot az ügyfél

(Tény, hogy vannak olyan 4. opció, a szerver aktívan egy kérést küld az ügyfél, és szeretné, hogy a választ. De én egy ilyen lehetőség volt, soha nem kellett, és nem vettem észre azt).

Az első esetben mi adjuk hozzá a ID kérés:

És megkapjuk a választ:

A második esetben, nem adjuk hozzá a kérés azonosítója:

Kapcsolódó cikkek