Az első számítógép-hálózatoknál a legfőbb tervezési szempont a hardver volt, és csak azután jött a szoftver. Ez a módszer ma már nem működik. A hálózati szoftverek nagymértékben strukturálódtak. A következő alfejezetekben a szoftverek strukturálási módját fogjuk részletesen megvizsgálni. Az itt leírt módszer kulcsfontosságú a könyv további részei szempontjából, és többször is vissza fogunk még térni rá.
A tervezés bonyolultságának csökkentése érdekében, a legtöbb hálózatot úgy alakítják ki, hogy azok egymásra épülő rétegeket vagy szinteket (layer, level) képezzenek. A rétegek száma, elnevezése, tartalma és feladata más és más a különböző hálózatokban. Minden réteg célja az, hogy bizonyos szolgáltatásokat (service) nyújtson a felette elhelyezkedő rétegeknek, miközben elrejti előlük a szolgáltatások tényleges megvalósításának részleteit. Egy lehetséges értelmezés szerint minden réteg egy olyan virtuális gép, amely a felette levő rétegek számára szolgáltatásokat nyújt.
Ez tulajdonképpen ismerős koncepció, amely a számítástechnika minden területén használatos. Hívják információelrejtésnek (information hiding), absztrakt adattípusok használatának, adatbeágyazódásnak (data encapsulation) és objektumorientált programozásnak (object-oriented programming, OOP) is. Az alapötlet az, hogy egy meghatározott szoftver- (vagy hardver-) elem szolgáltatást nyújt a felhasználóinak, de a belső állapotára és az algoritmusaira vonatkozó információt elrejtve tartja előlük.
Az egyik gép n-edik rétege párbeszédet folytat egy másik gép n-edik rétegével. A párbeszéd írott és íratlan szabályait együttesen az n-edik réteg protokolljának (protocol) nevezzük. A protokoll lényegében olyan megállapodás, amely az egymással kommunikáló felek közötti párbeszéd szabályait rögzíti. Egy analóg példával élve, amikor egy nőt bemutatnak egy férfinak, akkor a nőn múlik, hogy kinyújtja-e a kezét, a férfi pedig eldöntheti, hogy kezet fog vele vagy pedig kezet csókol neki. Hogy mi történik, az attól függ, hogy a hölgy egy üzleti tárgyaláson részt vevő amerikai ügyvédnő vagy egy bálon megjelenő európai hercegnő. A protokoll megsértése nagyban megnehezítené, sőt akár lehetetlenné is tenné a kommunikációt.
Az 1.13. ábrán egy ötrétegű hálózatot láthatunk. Azokat az entitásokat, amelyeket a különböző gépek azonos rétegei tartalmaznak, társentitásoknak (peer) nevezzük. Más szóval a társentitások azok az entitások, amelyek a protokoll segítségével kommunikálnak egymással.
A valóságban az egyik gép n-edik rétegéből az adatok nem közvetlenül jutnak át egy másik gép n-edik rétegébe, hanem valamilyen vezérlőinformációval kiegészítve mindegyik réteg közvetlenül az alatta levőnek továbbítja az adatokat egészen addig, amíg azok a legalsó rétegig el nem jutnak. Az első réteg alatt a fizikai közeg (physical medium) található, amelyen a valódi kommunikáció zajlik. Az 1.13. ábrán a virtuális kommunikációt szaggatott vonalakkal, a fizikai kommunikációt pedig folytonos vonalakkal jelöltük.
Az egymással szomszédos rétegek között interfész (interface) található. Az interfész azt definiálja, hogy az alacsonyabban levő réteg milyen elemi műveleteket és szolgáltatásokat nyújt a magasabban levő réteg számára. Amikor a hálózattervezők eldöntik, hogy hány réteget tartalmazzon egy hálózat, és hogy mi legyen az egyes rétegek feladata, akkor a legfontosabb szempont az, hogy a rétegek közötti interfész minél világosabb legyen. Ehhez persze az szükséges, hogy minden réteg jól definiált feladatokkal rendelkezzen. Azonkívül, hogy a rétegek közötti információcserét minimalizálják, a jól meghatározott interfészek azt is könnyebbé teszik, hogy valamelyik réteg tényleges megvalósítását lecseréljük egy teljesen újra (például lecseréljük az összes telefonvonalat műholdas kapcsolatra), mivel mindössze annyit várunk el az új megvalósítástól, hogy pontosan ugyanazokat a szolgáltatásokat nyújtsa a felette levő rétegnek, mint a korábbi megvalósítás. Gyakran előfordul, hogy a különböző hosztok egyazon protokoll eltérő (gyakran más cégek által készített) megvalósításait használják. Valójában a protokoll maga is megváltozhat valamelyik rétegben anélkül, hogy a fölötte vagy alatta található rétegek egyáltalán észrevennék.
A rétegek és protokollok halmazát hálózati architektúrának (network architecture) nevezzük. Az architektúra specifikációjának elegendő információt kell tartalmaznia ahhoz, hogy az implementálást végző szakember minden réteghez meg tudja írni a programot, illetve meg tudja építeni a hardvert úgy, hogy az helyesen alkalmazza a megfelelő protokollt. Az implementáció részletei és az interfészek specifikációja nem része az architektúrának, mivel ezek a gép belsejében rejtve maradnak, tehát kívülről nem láthatók. Az sem szükséges, hogy a hálózat összes gépén ugyanazok az interfészek legyenek, feltéve, hogy az összes gép helyesen használja a protokollokat. Ha egy adott rendszerben minden réteg egyetlen protokollal rendelkezik, akkor a rendszer protokolljainak összességét protokollkészletnek (protocol stack) nevezzük. A hálózati architektúrák, a protokollkészletek és maguk a protokollok alkotják a könyv leglényegesebb témáit.
A következő analógia talán segít a többréteges kommunikáció elvének megértésében. Képzeljünk el két filozófust (ők a 3. réteg társfolyamatai), akik közül az egyik urdu nyelven és angolul beszél, a másik pedig kínaiul és franciául. Mivel nincs közös nyelvük, ezért mindkettőjük egy-egy tolmácsot alkalmaz (ők a 2. réteg társfolyamatai). Mindkét tolmácsnak van egy titkárnője (ők az 1. réteg társfolyamatai). Az 1-es filozófus az oryctolagus cuniculus iránti ragaszkodását szeretné kifejezni a társának. Ahhoz, hogy ezt megtehesse, elküld egy üzenetet (angolul) a 2/3 interfészen keresztül a tolmácsának, ahogy ez az 1.14. ábrán is látható. Az üzenet tartalma a következő: „I like rabbits” („Szeretem a nyulakat”). A tolmácsok megegyeztek egy semleges nyelvben, a hollandban, így tehát az üzenet a következőképpen hangzik: „Ik wind konijnen leuk”. A nyelv megválasztása a 2. réteg protokolljának a feladata, és kizárólag ennek a rétegnek a társfolyamataitól függ.
A tolmács ezek után átadja az üzenetet a titkárnőnek, hogy továbbítsa azt, mondjuk faxon (1. réteg protokollja). Amikor a másik félhez megérkezik az üzenet, akkor azt lefordítják franciára, majd pedig tovább kerül a 2/3 interfészen keresztül a 2-es filozófushoz. Vegyük észre, hogy az egyes protokollok teljesen függetlenek egymástól, amennyiben az interfészek nem változnak. A tolmács hollandról átválthat mondjuk finnre, ha akar, feltéve, hogy megegyeztek benne, és egyikük sem változtatja meg az interfészt az 1. vagy a 3. réteg felé. Hasonlóképpen, a titkárnők fax helyett e-levelet vagy telefont is használhatnak anélkül, hogy megzavarnák (sőt anélkül, hogy egyáltalán tájékoztatnák) a többi réteget. További információt mindegyik folyamat csak a saját társfolyamatának küldhet. Ez az információ már nem jut el az eggyel magasabb réteghez.
Nézzünk meg most egy sokkal inkább műszaki jellegű példát. A kérdés az, hogy hogyan tegyük lehetővé a kommunikációt az 1.15. ábrán látható ötrétegű hálózat legfelső rétege számára. Az 5. rétegben egy alkalmazói folyamat létrehoz egy üzenetet (jelöljük ezt M-mel), majd átadja a 4. rétegnek, hogy továbbítsa azt. A 4. réteg az üzenet azonosítása céljából egy fejrészt (header) illeszt az üzenet elejére, és továbbadja a 3. rétegnek. A fejrész vezérlőinformációt tartalmaz, például címzést, hogy a fogadógépre a 4. rétegben megérkezhessen az üzenet. Az egyes rétegekben használt vezérlőinformáció más példái a sorszámozás (ha az alsóbb réteg nem őrzi meg az üzenetsorrendet), a méret és az idő megadása.
A 4. réteg által elküldött üzenetek mérete sok hálózatban tetszőlegesen nagy lehet, ugyanakkor a 3. réteg protokollja szinte minden hálózatban meghatároz egy maximális üzenethosszt. Következésképpen a 3. rétegnek kisebb egységekre, csomagokra kell bontania a felülről hozzá érkező üzeneteket, és minden csomagot ki kell egészítenie egy fejrésszel. Példánkban az M üzenetet két részre osztottuk: -re és
-re, melyek egymástó függetlenül továbbítódnak.
A 3. réteg kiválasztja a megfelelő kimeneti vonalat, majd továbbadja a csomagot a 2. rétegnek. A 2. réteg nem csak fejrészt, hanem egy farokrészt (trailer) is hozzácsatol a csomaghoz, és az így kapott egységet adja át az 1. rétegnek a fizikai továbbítás céljából. A vevő oldalon az üzenet rétegről rétegre felfelé halad, miközben a fejrészek leválnak róla. Az n-edik réteg alatti rétegek fejrészei sosem juthatnak el az n-edik rétegig.
Az 1.15. ábrán látható rajz kapcsán a legfontosabb az, hogy megértsük a különbséget a virtuális és a valódi kommunikáció, illetve a protokoll és az interfész között. Például a 4. réteg társfolyamatai a saját kommunikációjukat következetesen „horizontálisnak” tekintik, hiszen a 4. réteg protokollját használják. Valószínűleg mindkét folyamatnak van egy KüldésATúloldalra és egy VételATúloldalról nevű eljárása még akkor is, ha valójában nem közvetlenül egymással, hanem a 3/4 interfészen keresztül az alsóbb rétegekkel kommunikálnak.
A társfolyamat-absztrakció alapvetően fontos a hálózat tervezéséhez. Ez teszi ugyanis lehetővé, hogy a teljes hálózat megtervezésének átláthatatlanul bonyolult feladatát több kisebb, jól kezelhető tervezési feladatra osszuk, azaz, hogy az egyes rétegeket külön-külön tervezhessük meg.
Bár az 1.3. alfejezet címe „Hálózati szoftver”, érdemes megjegyezni, hogy a protokollhierarchia alacsonyabb szintjeit gyakran hardvereszközökkel vagy firmware-rel valósítják meg. Még bonyolult algoritmusokat is implementálnak hardverben.
A számítógép-hálózatok tervezésének legfontosabb kérdései rétegről rétegre haladva újra felmerülnek. Az alábbiakban a legfontosabbak közül emelünk ki néhányat.
A megbízhatóság kérdéskörébe az tartozik, hogy a hálózat annak ellenére is helyesen működjön, hogy önmagukban megbízhatatlan alkotóelemekből épül fel. Gondoljunk csak egy hálózaton keresztül utazó csomag bitjeire. Valamekkora eséllyel ezek a bitek sérülten (invertálva) érkeznek meg, melynek oka lehet véletlenszerű elektromos zaj, kiszámíthatatlan vezeték nélküli jelek, illetve hardver- vagy szoftverhibák és így tovább. Hogyan lehetséges mégis, hogy észrevegyük és kijavítsuk ezeket a hibákat?
A fogadott adatok hibáinak észrevételére, azaz a hibajelzésre (error detection) az egyik lehetséges módszer a kódolás használata. A hibásan vett adatokat újra lehet küldeni, mígnem egyszer csak helyesen érkeznek meg. Hathatósabb kódolás révén hibajavítás (error correction) is lehetséges, azaz a helyes üzenet helyreállítható a ténylegesen fogadott, esetlegesen hibás bitekből. Mindkét eljárás redundáns információ hozzáadásával működik. Az alsóbb rétegekben azért használják ezeket, hogy az egyes összeköttetéseken átküldött csomagokat védjék, míg a felsőbb rétegekben azt ellenőrzik, hogy a helyes adatok érkeztek-e válaszként.
Egy másik megbízhatósági kérdés a működő útvonalak megtalálása a hálózatban. Gyakran több lehetséges útvonal is létezik egy forrásállomás és egy célállomás között, és egy nagy hálózatban lehetnek meghibásodott kapcsolatok vagy útválasztók. Tegyük fel, hogy Németországban épp nem működik a hálózat. Ha Londonból Rómába Németországon keresztül küldenénk csomagokat, azok nem érnének célba, de ehelyett elküldhetnénk azokat Londonból Rómába Párizson keresztül is. A hálózatnak automatikusan kell meghoznia ezeket a döntéseket. Ezt a témakört útválasztásnak (routing) nevezzük.
A második tervezési problémakör a hálózat fejlődésével foglalkozik. Idővel a hálózatok nagyobbra nőttek, és újfajta elemeket kell a meglévő hálózathoz csatlakoztatni. Az előzőekben láttuk azt a kulcsfontosságú strukturálási módot, mely a teljes probléma felosztásával és a megvalósítás részleteinek elrejtésével segíti a változást: ez a protokollok rétegezése (protocol layering). De léteznek más stratégiák is.
Mivel a hálózatokban általában sok számítógép van összekötve, minden rétegben kell lennie egy olyan mechanizmusnak, amely egy üzenet küldőjét és vevőjét azonosítja. Ezt a mechanizmust címzésnek (addressing) nevezik az alsóbb, illetőleg névkezelésnek (naming) a felsőbb rétegek esetében.
A növekedés egyik velejárója az, hogy a különböző hálózati technikák gyakran más-más korlátokkal rendelkeznek. Például nem minden kommunikációs csatorna tartja meg a rajtuk elküldött üzenetek eredeti sorrendjét, ezért olyan megoldásokat kellett bevezetni, melyek sorszámozzák az üzeneteket. Egy másik példa a hálózatok által továbbítható üzenetek méretkorlátai közötti eltérés. Ez olyan eljárásokat igényel, melyek szétbontják, továbbítják, majd újra összerakják az üzeneteket. Ennek a teljes témának az összefoglaló neve internetworking, azaz a hálózatok összekapcsolásával foglalkozó terület.
Amikor a hálózatok nagyon nagyra nőnek, új problémák kerülnek elő. A városokban kialakulhatnak forgalmi dugók, elfogyhatnak a telefonszámok, és eltévedni is könnyű. Nem sok embernek okoz ez problémát a saját körzetében, de városi léptékben gondolkodva már nagy gondot okozhat. Azokat a kialakításokat, melyek akkor is jól működnek, amikor egy hálózat nagyra növekszik, skálázhatónak (scalable) nevezzük.
A harmadik tervezési kérdés az erőforrások kiosztása. A hálózatok az alattuk levő erőforrások felhasználása révén szolgálják a hosztokat. Ilyen erőforrás például az átviteli vonalak kapacitása. Hogy szolgáltatásukat jól végezhessék, olyan mechanizmusokra van szükségük, melyekkel úgy osztják fel az erőforrásaikat, hogy az egyik hoszt ne nagyon zavarja a másikat.
Sok konstrukcióban a sávszélesség kiosztása dinamikusan, a hosztok rövid távú szükségletei szerint történik ahelyett, hogy minden hoszt a teljes sávszélességnek egy rögzített hányadát kapná, melyet vagy kihasznál, vagy nem. Ezt a működési módot statisztikai multiplexelésnek (statistical multiplexing) hívjuk, ami azt jelenti, hogy az elosztás az igényekre vonatkozó statisztikák alapján történik. Ez a megoldás az alsóbb rétegekben alkalmazható egyetlen kapcsolatra, vagy a felsőbb rétegekben a teljes hálózatra, vagy akár a hálózatot használó alkalmazásokra is.
Minden rétegben felmerülő erőforrás-kiosztási probléma az, hogy hogyan akadályozzuk meg azt, hogy a gyorsabban adó gépek elárasszák adatokkal a lassabban vevőket. Ezek a módszerek gyakran a vevő és az adó közötti visszacsatoláson alapulnak. Ezt a témakört forgalomszabályozásnak (flow control) nevezzük. Néha viszont abból adódik a probléma, hogy túl sok számítógép kíván túl sok forgalmat átküldeni, és a hálózat nem képes mindent kézbesíteni. A hálózat ilyen túlterhelődését torlódásnak (congestion) hívjuk. Az egyik követhető stratégia az, hogy minden számítógép csökkentse az átviteli igényét, amikor torlódást tapasztal. Ez a módszer is használható minden rétegben.
Érdekes észrevétel, hogy egy hálózat a sávszélesség mellett más erőforrásokat is kínálhat. Olyan használati esetekben, mint az élő mozgókép továbbítása, nagyban számít az időben történő kézbesítés. A legtöbb hálózatnak egyszerre kell szolgáltatást nyújtania olyan alkalmazások számára, melyek valós idejű (real-time) továbbítást igényelnek, ugyanakkor nagy átbocsátóképességre van szükségük. Azoknak a mechanizmusoknak, melyek összeegyeztetik ezeket az egymással versengő igényeket, szolgáltatásminőségi mechanizmus (quality of service) a neve.
Az utolsó nagy tervezési kérdés a hálózat biztonságossá tétele azáltal, hogy megvédjük a különböző fenyegetések ellen. Az egyik fenyegetés, melyet már említettünk, a kommunikáció lehallgatása. A titkosságot (confidentiality) nyújtó technikák védenek ez ellen a veszély ellen, és több rétegben is használjuk ezeket. A hitelesítési (authentication) eljárások akadályozzák meg, hogy valaki egy másik szereplőt személyesítsen meg. Használhatók például arra, hogy megkülönböztessük a hamis banki weboldalakat a valódiaktól, vagy hogy a mobiltelefon-hálózat szolgáltatója megbizonyosodjon róla, hogy egy hívás valóban az Ön készülékéről jön, így Ön ki fogja fizetni a számlát. Más mechanizmusok a sértetlenséget (integrity) védik az üzenetek titokban történő módosítása ellen, mint például, ha a „Vonjon le a számlámról 10 dollárt!” üzenetet megváltoztatná valaki a „Vonjon le a számlámról 1000 dollárt!” üzenetre. Az összes felsorolt elv a kriptográfián alapul, melyet a 8. fejezetben fogunk tanulmányozni.
A rétegek két különböző szolgáltatást[6] nyújthatnak a felettük levő rétegek számára: összeköttetés-alapú és összeköttetés nélküli szolgáltatást. Ebben az alfejezetben ezt a két szolgáltatástípust vizsgáljuk meg, és ismertetjük a kettő közötti különbségeket is.
Az összeköttetés-alapú szolgáltatás (connection-oriented service) a távbeszélőrendszerrel modellezhető. Ahhoz, hogy valakivel beszélni tudjunk, fel kell emelnünk a telefonkagylót, tárcsázni kell a számot, ezután beszélgethetünk, majd végül le kell tennünk a telefont. Hasonló módon, egy összeköttetés-alapú hálózati szolgáltatás igénybevételéhez a szolgáltatást igénybe vevő felhasználó először létrehozza az összeköttetést, majd felhasználja, végül pedig lebontja azt. Az összeköttetés lényege az, hogy úgy működik, mint egy cső: az adó a cső egyik végén belerakja a dolgokat (biteket), a vevő pedig a másik végén ugyanabban a sorrendben kiveszi azokat. A legtöbb esetben a bitek sorrendje megmarad, vagyis ugyanabban a sorrendben érkeznek meg, mint ahogyan elküldték őket.
Egyes esetekben az összeköttetés létesítését követően a küldő fél, a fogadó fél és az alhálózat egyezkedésbe (negotiation) kezdenek az olyan használandó paraméterekkel kapcsolatban, mint például az üzenetek maximális hossza, a kívánt szolgáltatásminőség és más hasonló kérdések. Általában valamelyik fél javasol valamit, amit a másik fél elfogadhat vagy elutasíthat, illetve ellenjavaslatot is tehet. Az áramkör (circuit) egy másik elnevezése az olyan összeköttetésnek, mely hozzárendelt erőforrásokkal rendelkezik, például rögzített sávszélességgel. Ez a telefonhálózatokból eredeztethető, ahol az áramkör azt a rézvezetékből álló útvonalat jelentette, amin egy beszélgetés zajlott.
Ezzel szemben az összeköttetés nélküli szolgáltatás (connectionless service) a levéltovábbító postai rendszerrel modellezhető. Minden egyes üzenet (levél) rendelkezik egy teljes célcímmel, és minden üzenet az összes többitől független útvonalon továbbítódik a rendszer köztes csomópontjain keresztül. Az üzeneteket eltérő kontextusban különféleképpen nevezhetjük: a csomag (packet) a hálózati réteg szintjén levő üzenet. Azt a működési módot, amikor a köztes csomópont teljes hosszában fogad egy üzenetet, mielőtt továbbküldené a következő csomópontnak, tárol-és-továbbít típusú kapcsolásnak (store-and-forward switching) nevezzük. Ennek az alternatíváját, mely során az üzenet továbbküldése már azelőtt megkezdődik, mielőtt a csomópont teljességében megkapná, átfuttató kapcsolásnak (cut-through switching) hívjuk. Ha két üzenetet küldünk ugyanarra a címre, akkor általában az ér oda előbb, amelyiket előbb küldtük el. Persze az is lehetséges, hogy az elsőnek elküldött üzenet annyit késik, hogy a második ér oda előbb.
Minden szolgáltatás jellemezhető a megbízhatósági fokával is. Bizonyos szolgáltatások megbízhatók abban az értelemben, hogy sosem vesztenek el adatot. Egy megbízható szolgáltatást rendszerint úgy valósítanak meg, hogy a vevőnek minden megkapott üzenetet nyugtáznia kell, így a küldő biztos lehet abban, hogy az üzenet megérkezett. A nyugtázási folyamat plusz időt és késleltetést jelent, ami legtöbbször megéri, de persze van, amikor nem kívánatos.
A megbízható összeköttetés-alapú szolgáltatás egyik tipikus alkalmazása a fájlátvitel (file transfer). A fájl tulajdonosa biztos szeretne lenni abban, hogy az összes bit rendben megérkezik, és ráadásul ugyanabban a sorrendben, ahogy elküldte. Kevés olyan felhasználó van, aki fájlátvitelnél olyan szolgáltatást részesítene előnyben, amelyik időnként összekever vagy elveszt néhány bitet. Még akkor sem vennének igénybe olyat, ha az sokkal gyorsabb lenne.
A megbízható összeköttetés-alapú szolgáltatásoknak két altípusa van: az üzenetsorozat és a bájtfolyam. Az első esetben megmaradnak az üzenethatárok. Ha elküldünk két 1024 bájtos üzenetet, akkor azok mindig két különálló 1024 bájtos üzenet formájában érkeznek meg, és sohasem egy 2048 bájtos üzenetként. A második esetben viszont az összeköttetés egyszerűen csak egy bájtfolyam, és nincsenek üzenethatárok. Ha egy 2048 bájtos üzenet érkezik a vevőhöz, akkor sehogy sem tudja megállapítani, hogy azt két 1024 bájtos üzenet, egy 2048 bájtos üzenet vagy 2048 darab egybájtos üzenet formájában küldték-e el. Ha egy könyv oldalait a hálózaton egyenként, külön üzenetek formájában küldjük el egy fényszedő gépre, akkor fontos, hogy megmaradjanak az üzenethatárok. Amikor viszont egy DVD-filmet töltünk le, akkor csak arra van szükségünk, hogy a bájtfolyam a szerverről eljusson a számítógépünkre. A filmen belül az üzenethatároknak nincs jelentősége.
Bizonyos alkalmazások esetén a nyugtázásból adódó késleltetés elfogadhatatlan. Ilyen alkalmazás például a digitalizált hangforgalom az IP-hálózaton keresztül történő hangátvitelben (Voice over IP, VoIP). A telefonon beszélgetők számára sokkal inkább elfogadható az, hogy néha egy kis zajt halljanak a vonalon, mint az, hogy a nyugtázások miatt késleltetés jelenjen meg. Hasonlóképpen, videokonferencia továbbításakor néhány hibás pixel még nem jelent problémát, viszont annál idegesítőbb, amikor a kép az átviteli hibák kijavítása miatt folyton megakad.
Nem minden kapcsolat igényel összeköttetést. Például a kéretlen reklámok küldői (spammer) nagyon sok címzettnek küldenek levélszemetet (junk mail). A levélszemetet küldő felhasználók valószínűleg nem akarnak azzal küszködni, hogy minden egyes levél elküldésekor felépítsenek, majd lebontsanak egy összeköttetést. Még csak a 100%-os kézbesítési arány sem fontos, különösen akkor nem, ha még drágább is. Csak arra van szükség, hogy egy olyan lehetőség nyíljon az üzenetek elküldésére, ami nagy valószínűséggel célba juttatja azokat, de erre garanciát nem vállal. A nem megbízható (tehát nem nyugtázott) összeköttetés nélküli szolgáltatást gyakran datagramszolgáltatásnak (datagram service) is hívják a távirat analógiájára, amelynél szintén nem lehet nyugtát küldeni a feladónak. Annak ellenére, hogy nem megbízható, a későbbiekben tisztázandó okok miatt a legtöbb hálózatban ez az uralkodó szolgáltatástípus.
Vannak olyan esetek, amikor kényelmesebb az, ha nem létesítünk összeköttetést egy rövidebb üzenet továbbításához, de a megbízhatóság alapvető fontosságú. Ezekben az esetekben nyugtázott datagramszolgáltatásot (acknowledged datagram service) érdemes igénybe venni, ami olyan, mint a tértivevényes levélkézbesítés. Amikor a feladó megkapja a tértivevényt, akkor teljesen biztos lehet abban, hogy a levelet kikézbesítették a címzettnek, és nem veszett el útközben. A mobiltelefonon történő szöveges üzenetküldés példázza ezt a működést.
Egy újabb szolgáltatás a kérés-válasz szolgáltatás (request-reply service). Ennél a szolgáltatásnál az adó datagram formájában elküld egy kérést, amire érkezik a válasz. Kérés-válasz szolgáltatást használunk leggyakrabban a kliens–szerver-modell szerinti kommunikáció megvalósításakor: a kliens küld egy kérést, melyre a szerver válaszol. Például egy mobiltelefon-kliens küldhet egy lekérdezést egy térképszervernek, hogy elkérje tőle az aktuális pozíciója körüli térképadatokat. Az eddig tárgyalt szolgáltatástípusokat az 1.16. ábrán látható táblázatban foglaltuk össze.
Az a tény, hogy megbízhatatlan kommunikációt használunk, elsőre nagyon zavarónak tűnhet. Tulajdonképpen miért is részesítené bárki a megbízható kommunikációval szemben a megbízhatatlan kommunikációt előnyben? Először is, megbízható (vagyis a mi értelmezésünk szerinti nyugtázott) kommunikáció esetleg nem érhető el az adott rétegben. Például az Ethernet nem biztosít megbízható kommunikációt. A csomagok néha megsérülhetnek a továbbítás során. Ennek a problémának a megoldása a magasabb szintű protokollok feladatkörébe tartozik. Másodszor, a megbízható szolgáltatással szükségszerűen együtt járó nagyobb késleltetések elfogadhatatlanok lehetnek, különösen az olyan valós idejű alkalmazásokban, mint például a multimédia-alkalmazások. Mindezen okok indokolják mind a megbízható, mind a megbízhatatlan kommunikáció együttélését, létezését.
Egy szolgáltatást formálisan a primitívek (primitives) vagy elemi műveletek (operations) olyan halmazával adhatunk meg, amelyek az azt igénybe vevő folyamat számára rendelkezésre állnak a szolgáltatás eléréséhez. A primitívekkel egy művelet elvégzésére lehet utasítást adni egy szolgáltatónak, vagy beszámolót lehet kérni egy társentitás tevékenységéről. Amennyiben a protokollkészlet az operációs rendszerben található (ez gyakran van így), a primitívek általában rendszerhívások. Ezek a hívások rendszermódba (kernel mode) kényszerítik a számítógépet, vagyis az operációs rendszernek adják át a gép feletti irányítást, amely így el tudja küldeni a szükséges csomagokat.
A szolgáltatás természete meghatározza a rendelkezésre álló primitívek készletét. Egy összeköttetés-alapú szolgáltatásnak más primitívjei vannak, mint egy összeköttetés nélkülinek. Az 1.17. ábrán szolgáltatási primitívek egy olyan legkisebb készlete látható, amely már alkalmas lehet megbízható bájtfolyam megvalósítására kliens–szerver-környezetben. Ismerősen fognak csengni a Berkeley-csatlakozó határfelület rajongói számára, mivel a primitívek ennek az interfésznek az egyszerűsített változatai.
1.17. ábra - Hat szolgáltatási primitív egy egyszerű összeköttetés-alapú szolgáltatás megvalósításához
Ezek a primitívek felhasználhatók például egy kérés-válasz típusú párbeszédhez kliens–szerver-környezetben. Ennek szemléltetésére vázoljunk fel egy egyszerű, nyugtázott datagramszolgáltatást megvalósító protokollt.
Először a szerver végrehajt egy listen primitívet, amellyel azt jelzi, hogy felkészült a bejövő összeköttetések fogadására. A listen-t gyakran egy blokkoló hatású rendszerhívással valósítják meg. Miután a primitívet végrehajtotta, a szerverfolyamat addig nem lép tovább, amíg az összeköttetés létesítésére kérés nem érkezik.
Ezt követően a kliensfolyamat egy connect primitívet hajt végre, hogy összeköttetést építsen ki a szerver felé. A connect hívásban meg kell jelölni, hogy kihez akarunk kapcsolódni, ezért általában egy paraméterben szerepel a szerver címe is. Az operációs rendszer ilyenkor általában egy csomagot küld el a társentitásnak, amellyel az összeköttetés-létesítési kérést jelzi, amint azt (1) is mutatja az 1.18. ábrán. A kliensfolyamatot ekkor a rendszer felfüggeszti addig, amíg válasz nem érkezik.
Amikor a csomag megérkezik a szerverhez, azt az ottani operációs rendszer dolgozza fel. Amikor a rendszer azt látja, hogy a csomagban összeköttetés-létesítési kérés van, megnézi, hogy van-e olyan folyamat, amelyik erre vár. Ha van, akkor megszünteti a várakozó folyamat blokkolását. A kiszolgáló folyamat ilyenkor létrehozhatja a kapcsolatot az accept hívással. Ez egy nyugtát (2) küld vissza a kliens folyamat számára, jelezve a kapcsolat elfogadását. Ennek a nyugtának a megérkezése futó állapotba helyezi a klienst. Ezen a ponton a kliens és a szerver egyaránt fut, és közöttük az összeköttetés létrejött.
1.18. ábra - Egy egyszerű kliens–szerver-kommunikáció nyugtázott datagramszolgáltatás használata esetén
Nyilvánvaló párhuzam látszik az itt leírt protokoll és az élet között, például abban az esetben, amikor egy ügyfél (kliens) felhívja egy cég ügyfélszolgálatát. Az ügyfélszolgálat munkatársa reggelente odaül a telefonhoz, hátha az csörögni fog. Később az ügyfél hívást kezdeményez, és amikor az ügyfélszolgálat munkatársa felveszi a telefont, az összeköttetés létrejön.
A szerver számára a következő lépés egy receive primitív végrehajtása, amellyel felkészül az első kérés fogadására. Általában ezt a szerver azonnal megteszi, amint továbbindul a listen hívást követő blokkolódás után, még mielőtt a nyugta megérkezhetne a klienshez. A receive meghívása blokkolja a szervert.
Ez után a kliens egy send primitívet hajt végre a kérés (3) elküldésére, amelyet egy receive végrehajtása követ azért, hogy a választ venni tudja. Amikor a kérést tartalmazó csomag megérkezik a szervergépre, a rendszer továbbindítja a szerverfolyamatot, hogy az feldolgozhassa a kérést. Miután elvégezte a kért munkát, a szerverfolyamat egy send segítségével küldi el a választ (4) a kliensnek. Ennek a csomagnak a megérkezése továbbindítja a klienst, amely így megnézheti a választ. Ha további kérései vannak, azokat most küldheti el.
Ha a kliens befejezte a munkát, a disconnect primitív segítségével szüntetheti meg az összeköttetést (5). Általában az első disconnect egy blokkoló hívás, amely felfüggeszti a klienst, és egy csomagot küld el a szervernek, amellyel azt közli vele, hogy a kapcsolatra nincsen tovább szüksége. Amikor a szerver megkapja ezt a csomagot, szintén egy disconnect hívást hajt végre, amellyel nyugtázza a kérést a kliens felé és elengedi a kapcsolatot (6). Amikor a szerver csomagja visszaérkezik a klienshez, a kliensfolyamat továbbindul, és az összeköttetés megszakad. Röviden összefoglalva így működik az összeköttetés-alapú kommunikáció.
Természetesen az élet nem ennyire egyszerű. Ebben a rendszerben sok minden el tud romlani. Lehet rossz az időzítés (például a connect előbb van, mint a listen), elveszhetnek csomagok, és még sok más hibaforrás is lehet. Ezeket a dolgokat később még részletesen meg fogjuk tárgyalni, de pillanatnyilag az 1.18. ábrán látható modell elégségesen összefoglalja, hogyan működik a kliens–szerver-kommunikáció nyugtázott datagramok használata esetén, hogy figyelmen kívül hagyhassuk a csomagvesztést.
Azt látva, hogy az összeköttetés felépítéséhez ebben a protokollban hat csomagra van szükség, felmerülhet az olvasóban az a kérdés, hogy miért nem használunk inkább összeköttetés nélküli protokollt. A válasz az, hogy egy tökéletes világban használhatnánk ilyet, és mindössze két csomagra lenne szükség: egy a kéréshez és egy a válaszhoz. Amikor azonban nagyobb üzeneteket kell továbbítani (például egy néhány megabájtos állományt), történhetnek átviteli hibák és csomagvesztések is, máris egy teljesen más helyzetben találjuk magunkat. Ha a válasz több száz csomagból áll, és ezek közül néhány elveszhet az átvitel során, honnan tudhatná a kliens, hogy ténylegesen elveszett-e valami útközben. Honnan tudhatná a kliens, hogy az utolsónak érkezett csomag az utolsónak feladott-e? Most tegyük fel, hogy a kliens még egy állományt kér. Hogyan tudná megkülönböztetni a második állomány első csomagját az első állomány korábban elveszett első csomagjától, ami hirtelen mégis megérkezik? Röviden összefoglalva, egy egyszerű kérés-válasz protokoll gyakran nem alkalmas arra, hogy megbízhatatlan hálózaton alkalmazzuk. A 3. fejezetben egy sor olyan protokollt fogunk megvizsgálni, amelyek megoldják ezt és más problémákat is. Egyelőre azonban elég azt kijelentenünk, hogy néha az igényeknek nagyon megfelel, ha egy megbízható bitfolyam áll rendelkezésre a folyamatok között.
A szolgáltatás és a protokoll különböző fogalmak, mégis gyakran összekeverik őket. A kettő közötti különbség nagyon fontos, ezért ismételten szeretnénk azt hangsúlyozni. A szolgáltatás nem más, mint olyan primitívek (elemi műveletek) halmaza, amelyet egy adott réteg a felette levő rétegek számára biztosít. A szolgáltatás azt definiálja, hogy egy réteg a felhasználó nevében milyen műveleteket képes végrehajtani, de arról nem mond semmit, hogy mindezt hogyan kell implementálni. A szolgáltatás két szomszédos réteg közötti interfésszel kapcsolatos, ahol az alsó réteg a szolgáltató, a felső réteg pedig a szolgáltatás felhasználója.
Ezzel szemben a protokoll olyan szabályok halmaza, amelyek azt mondják meg, hogy milyen legyen a formátuma és mi legyen a jelentése azoknak a kereteknek, csomagoknak és üzeneteknek, amelyeket egy adott rétegen belül a társentitások küldözgetnek egymásnak. Az entitások a protokollokat használják arra, hogy a szolgáltatásdefiníciókat implementálják. Ha akarják, szabadon megváltoztathatják a protokolljaikat, feltéve, hogy a felhasználó számára látható szolgáltatások ettől nem változnak meg. Ily módon a szolgáltatást és a protokollt teljesen ketté lehet választani. Ez egy kulcsfontosságú elgondolás, melyet minden hálózattervezőnek jól kell értenie.
Másképp megfogalmazva: a szolgáltatások a rétegek közötti interfésszel kapcsolatosak, ahogyan az az 1.19. ábrán is látható. Ezzel szemben a protokollok a különböző gépeken elhelyezkedő társentitások között elküldött csomagokkal kapcsolatosak. Fontos, hogy ne keverjük össze e két fogalmat.
Érdemes összehasonlítást tenni a programozási nyelvekkel. A szolgáltatás olyan, mint egy absztrakt adattípus vagy egy objektum egy objektumorientált nyelvben. Definiálja azokat a műveleteket, amelyeket az objektumon végre lehet hajtani, de nem mondja meg, hogy a műveleteket hogyan kell implementálni. A protokoll a szolgáltatás implementációjának felel meg, és mint ilyen, láthatatlan a szolgáltatást igénybe vevő számára.
Sok régebbi protokoll nem tett különbséget a szolgáltatás és a protokoll között. Ezekben egy tipikus réteg akár egy olyan send packet szolgáltatási primitívvel is rendelkezhetett volna, amelyet a felhasználónak egy teljesen összeállított csomagra mutató pointert biztosít. Ez azt jelenti, hogy a protokoll minden változása azonnal látható volt a felhasználó számára. A legtöbb hálózattervezéssel foglalkozó szakember az ilyen protokollokat nagy baklövésnek tartja.
[6] Az angol service szónak a magyar nyelvben számítógépes és kommunikációs környezetben mind a szolgálat, mind a szolgáltatás megfelelője használatos. Ebben a könyvben a szolgáltatás szót használjuk. (A lektor megjegyzése)