Pro správné pochopení podstaty celého problému je třeba si uvědomit, že realizace spolehlivých služeb je spojena s větší režií, než jakou jsou zatíženy nespolehlivé přenosové služby. Nejde přitom jen o větší výpočetní náročnost, ale také o větší nároky na přenosovou kapacitu. Spolehlivost přenosů po ne zcela spolehlivých přenosových cestách se totiž musí zajišťovat vhodnou formou potvrzování, což je ale vždy spojeno s přenosem určitého objemu služebních dat, ke kterému samozřejmě dochází na úkor "užitečných dat".
Jestliže tedy TCP/IP model požaduje na síťové vrstvě pouze nespolehlivou přenosovou službu (realizovanou protokolem IP, viz minulý díl), umožňuje tím současně, aby síťová vrstva pracovala s menší režií, a tudíž rychleji.
Spolehlivost vs. rychlost
Považuje-li síťový model TCP/IP otázku zajištění spolehlivosti za úkol koncových účastníků komunikace, znamená to, že příslušné mechanismy pro její zajištění musí být implementovány ve vyšší vrstvě, než je vrstva síťová. Otázkou ovšem je, zda to skutečně musí být již vrstva bezprostředně vyšší, tedy vrstva transportní - jak jsme dosud předpokládali.
Zařadit potřebné mechanismy pro zajištění spolehlivosti do transportní vrstvy má četné výhody. Především pak tu, že tyto prostředky mohou být v transportní vrstvě realizovány právě jednou, a sdíleny všemi entitami aplikační vrstvy. Pokud bychom naopak tyto prostředky umístili až do vrstvy aplikační, vlastně by to znamenalo, že by si je musela každá entita aplikační vrstvy zajišťovat vždy znovu a sama.
Mohlo by se tedy zdát, že vše hovoří ve prospěch první možnosti. Ale i ta druhá může mít své opodstatnění - existují totiž i takové druhy aplikací, které buď vůbec nepotřebují spolehlivé přenosové služby, nebo naopak nepovažují "spolehlivost" na úrovni transportní vrstvy za dostatečnou, a tak si ji musí zajišťovat samy a znovu. Jinou motivací mohou být otázky efektivnosti - některé aplikace si dokáží zajistit samy takovou míru spolehlivosti, jakou skutečně potřebují, a vykazují přitom menší režii, než jakou na zajištění "úplné" spolehlivosti vyžaduje vrstva transportní. Příkladem takovéhoto druhu aplikací může být distribuovaný systém souborů NFS (Network File System) firmy Sun, velmi oblíbený a značně rozšířený v prostředí operačního systému Unix. Umožňuje, aby jeden uzlový počítač zcela transparentně sdílel soubory jiného uzlového počítače, tedy aby k nim přistupoval naprosto stejně, jako ke svým vlastním souborům. Nemá-li ale docházet k výraznějším časovým rozdílům při přístupu k lokálním a vzdáleným souborům, musí systém NFS pracovat maximálně rychle. Nemůže si proto dovolit používat spolehlivé, zato ale "pomalé" přenosové služby na úrovni transportní vrstvy.Každý si může vybrat sám
TCP/IP Síťový model TCP/IP vychází vstříc oběma skupinám aplikací - jak těm, které na transportní vrstvě požadují spolehlivý přenos, tak i těm, které jej chtějí mít co možná nejrychlejší. Součástí rodiny protokolů TCP/IP jsou totiž dva alternativní protokoly pro transportní vrstvu: protokol TCP (Transmission Control Protocol), který zajišťuje spolehlivou přenosovou službu, a protokol UDP (User Datagram Protocol), který naopak nabízí službu nespolehlivou, s výrazně nižší režií, a tudíž rychlejší. Jednotlivé protokoly aplikační vrstvy si pak mezi oběma protokoly transportní vrstvy mohou vybrat ten, který jim lépe vyhovuje, případně využívat oba.
Spojovaný vs. nespojovaný charakter transportních služeb
Spolehlivost a nespolehlivost není jediným rozdílem mezi oběma protokoly transportní vrstvy. Protokol TCP má spojovaný (connection-oriented) charakter, který pracuje s virtuálními okruhy (virtual circuits), a před vlastním přenosem předpokládá navázání spojení mezi odesilatelem a příjemcem. Naproti tomu protokol UDP má nespojovaný (connectionless) charakter, a každý jednotlivý blok dat, označovaný v tomto případ jako uživatelský datagram (user datagram) přenáší samostatně a nezávisle na ostatních datagramech.Protokol UDP tak vlastně poskytuje na úrovni transportní vrstvy služby stejného charakteru, jaké na úrovni vrstvy síťové poskytuje protokol IP (viz minule), tedy nespolehlivé a nespojované služby. Naproti tomu protokol TCP implementuje pomocí nespolehlivých a nespojovaných služeb na úrovni síťové vrstvy spolehlivé a spojované transportní služby. Jak jsme si již naznačili výše, činí tak s pomocí mechanismu potvrzování (acknowledgement), a tudíž i s nezanedbatelnou režií.
Proud vs. blokově orientovaný přenos
Další odlišností mezi oběma protokoly je pak také forma, jakou své přenosové služby nabízí. Protokol UDP koncipuje svou přenosovou službu jako přenos celých bloků dat. Očekává tedy, že entita aplikační vrstvy, která chce odeslat nějaká data, je sama sestaví do bloku, a ten pak protokolu UDP předá jako jeden celek. Protokol UDP tento blok vezme, umístí jej do svého uživatelského datagramu (viz výše), a přenese opět jako jeden celek. Naproti tomu protokol TCP koncipuje svou přenosovou službu jako tzv. proud (stream) jednotlivých bytů (přesněji: osmic bytů, tzv. oktetů). Odesilatel na jednom uzlovém počítači postupně předává protokolu TCP jednotlivé byty (oktety), a obdobně postupuje i příjemce, který si je na druhé straně zase postupně odebírá. Veškeré členění přenášených dat na bloky a přenos celých těchto bloků zajišťuje protokol TCP plně transparentně. Uživatelé přenosových služeb protokolu TCP tak získávají iluzi, že pracují se službou, která přenáší individuálně jednotlivé byty (oktety).
Stavový vs. bezestavový způsob komunikace
Se spojovaným, resp. nespojovaným charakterem protokolů TCP a UDP úzce souvisí ještě i další aspekt, který je velmi podstatný pro protokoly aplikační vrstvy a pro jejich volbu mezi oběma nabízenými transportními protokoly. Každý uživatelský datagram (user datagram) - jak je označován blok dat, přenášený na úrovni transportní vrstvy protokolem UDP - je považován za samostatný celek, a vzhledem k nespojovanému charakteru protokolu UDP je také tak přenášen - samostatně, nezávisle na jiných uživatelských datagramech, a bez předchozího navázání spojení mezi příjemcem a odesilatelem. Stejně tak i příjemce chápe uživatelský datagram jako jediný celek, a ne jako součást většího celku. Tomu pak odpovídá i skutečnost, že příjemce nemění svůj stav v závislosti na průběhu komunikace - po přijetí datagramu se nachází ve stejném stavu, v jakém byl před jeho přijetím. Jde tedy o způsob přenosu, který je možné charakterizovat jako bezestavový (stateless). Naproti tomu každá spojovaná služba má vždy nutně stavový charakter, neboť již pouhým navázáním spojení se příjemce dostává do jiného stavu, než v jakém byl předtím.Bezestavový způsob komunikace je vzhledem ke své podstatě dobře odolný vůči různým nestandardním situacím, především pak výpadkům a ztrátám dat. Dojde-li například k výpadku přenosových cest či k výpadku příjemce (a je nutné jej znovu spustit, provést tzv. reboot), nejsou nutná žádná specifická opatření pro obnovu původního stavu - v přenosu dat se jednoduše pokračuje dál. Naproti tomu v případě stavového způsobu komunikace mohou být určité nápravné akce zapotřebí, má-li být zachována konzistence právě probíhajících činností, a znovu navázáno přerušené spojení.
S tím pak také souvisí i otázka spolehlivosti - zatímco bezestavové protokoly si mohou dovolit být nespolehlivé (jako UDP), pro jejich stavové protějšky je výhodnější pracovat s dostatečnou mírou spolehlivosti, a tedy nabízet spolehlivé přenosové služby (jako protokol TCP). Transportní protokoly TCP/IP - II. V minulém dílu našeho seriálu jsme se začali zabývat transportní vrstvou síťového modelu TCP/IP. Seznámili jsme se se dvěma alternativními protokoly - TCP a UDP - které jsou na této úrovni k dispozici, a zabývali jsme se především jejich odlišnostmi. Dnes se podrobněji zastavíme u toho, co mají oba transportní protokoly společného.Až doposud jsme v našich úvahách předpokládali, že prvotními odesilateli a konečnými příjemci nejrůznějších dat v počítačových sítích jsou jednotlivé uzlové počítače jako takové. Nyní si však musíme tuto představu upřesnit: skutečnými odesilateli a příjemci jsou entity aplikační vrstvy. Tyto mohou být označovány různě: jako procesy (processes), úlohy (tasks), aplikační programy (application programs) či ještě jinak. Podstatné ovšem je, že v prostředí víceúlohových operačních systémů takovýchto entit může být (a také bývá) více. Oba protokoly transportní vrstvy pak potřebují podle něčeho rozhodnout, které entitě aplikační vrstvy mají přijatá data předat.
Adresy procesů?
Nejjednodušší by bylo adresovat jednotlivá data přímo konkrétním procesům. Tedy přidělit procesům jednoznačné identifikátory, a ty pak používat pro určení koncových příjemců v rámci příslušného hostitelského počítače. Problém je ovšem v tom, že procesy vznikají a zanikají dynamicky, a odesilatel obvykle nemá dostatek informací o tom, které konkrétní procesy právě běží na cílovém počítači. Kdyby tomu tak mělo být, při vzniku či zániku každého procesu by museli být průběžně informováni všichni potenciální odesilatelé, což není prakticky možné. Pro odesilatele navíc nemusí být vůbec podstatné, který konkrétní proces bude příjemcem jeho dat. Data, která proces na jednom počítači posílá na jiný počítač, totiž mohou představovat požadavek na určitou službu. Pak ale není relevantní to, který proces právě zajišťuje danou službu, jako spíše to, o jakou službu jde. Navíc je docela dobře možné, že jeden a tentýž proces zajišťuje více jak jednu službu současně.Adresovat data konkrétním procesům tedy není příliš rozumné. Jaké jsou ale alternativy?
Porty a jejich vlastnosti
Další možností je vytvořit na rozhraní mezi transportní vrstvou a bezprostředně vyšší vrstvou "přechodové body", a ty opatřit jednoznačnými identifikátory, resp. adresami. Přenášená data pak jsou adresována těmto "přechodovým bodům", a skutečným příjemcem dat je pak ten proces, který je v daném okamžiku k tomuto "přechodovému bodu" logicky připojen.
Síťový model TCP/IP používá právě tento mechanismus, a příslušné "přechodové body" označuje jako porty (ports).
Z pohledu procesu, který je právě připojen k určitému portu, se tento jeví jako vyrovnávací paměť s režimem fronty - entita transportní vrstvy ukládá data do portu z jedné strany, a entita aplikační vrstvy (tj. proces) si je ve stejném pořadí zase odebírá. Analogicky i pro opačný směr přenosu. Samotný port s právě naznačenými vlastnostmi je sám o sobě datovou strukturou, a jako takový může dynamicky vznikat i zanikat, obdobně jako vlastní procesy.
Adresy portů
Vztah mezi portem a procesem (entitou aplikační vrstvy) je vztahem dynamickým - procesy se dynamicky připojují a odpojují od jednotlivých portů. Pro odesilatele je tedy podstatné znát čísla (adresy) jednotlivých portů, a nemusí pro ně být relevantní, který konkrétní proces je k příslušnému portu právě připojen. Chce-li například určitý proces na hostitelském počítači A získat soubor, který se nalézá na počítači B, musí svůj požadavek na tento soubor adresovat počítači B (který určí jeho IP adresou), a doplnit jej adresou portu, na kterém je zajišťována služba pro přenos souborů. Adresy portů jsou přitom celými čísly bez znaménka, v rozsahu 16 bitů. Otázkou ovšem je, jak může aplikační proces na jednom hostitelském počítači zjistit potřebná čísla portů na jiném počítači, ať již chce využít některou z jím poskytovaných služeb, nebo jinak komunikovat s některým z aplikačních procesů na tomto jiném počítači.K řešení této otázky jsou v zásadě dva možné přístupy. První z nich spočívá v tom, že čísla portů se na všech hostitelských počítačích přidělí jednou provždy a stejně, a toto přidělení se zveřejní. Každý aplikační proces pak má k dispozici informaci o číslech příslušných portů na všech uzlových počítačích - těmto portům se pak také říká dobře známé porty (well-known ports). Problém je ovšem v tom, že tato varianta statického charakteru se dá použít jen pro zveřejnění takových služeb, které jsou předem známy, a s jejichž existencí lze předem počítat.
Alternativou je umožnit procesům na jiných uzlových počítačích zjistit si číslo portu na daném počítači - dotazem stylu: "na jakém portu je poskytována služba přenosu souborů?" Tato varianta stále vyžaduje alespoň jeden "dobře známý port" (přes který by bylo možné vznést příslušný dotaz), a je také spojena s určitou režií. Na druhé straně je ale mnohem pružnější, neboť umožňuje vytvářet porty a přidělovat jim čísla (adresy) podle okamžité potřeby dynamicky vznikajících a zanikajících aplikačních procesů, a není vázána tím, jak jsou obdobná přidělení realizována na jiných uzlových počítačích.
Tvůrci TCP/IP protokolů se rozhodli pro kombinaci obou variant - pro nejčastěji používané služby použili první možnost, tedy pevné přidělení čísel "dobře známým portům", a zbylé adresy ponechali volné pro dynamické přidělování podle okamžitých potřeb.
Multiplex a demultiplex datagramů
Vraťme se nyní zpět k oběma protokolům transportní vrstvy soustavy TCP/IP, tedy k protokolům UDP a TCP. Z existence více portů mezi transportní a aplikační vrstvou vyplývá, že protokol transportní vrstvy na straně odesilatele musí být schopen přijímat data od různých aplikačních entit, a předávat je síťové vrstvě (realizované pomocí protokolu IP) k přenosu - tedy zajišťovat jejich multiplexování, a na straně příjemce pak provádět jejich demultiplexování, tedy rozdělování dat, převzatých od síťové vrstvy, mezi různé entity aplikační vrstvy, prostřednictvím příslušných portů.
Tato představa velmi dobře odpovídá koncepci nespojované přenosové služby, kterou poskytuje protokol UDP. Tento protokol se na každý port dívá skutečně jako na jeden logický objekt - frontu, do které jsou postupně ukládány všechny datagramy, adresované tomuto portu na daném počítači.
Protokol TCP však vychází z poněkud odlišné abstrakce. Vzhledem ke svému spojovanému charakteru pracuje se spojeními, která jsou definována dvěma koncovými body - každý koncový bod je přitom určen dvojicí . Více různých spojení přitom může sdílet tentýž koncový bod, tj. "končit" ve stejném portu. Základním typem objektu, se kterým protokol TCP pracuje, je tedy spojení, a nikoli port jako takový.
Protokol UDP
V předchozích dílech našeho seriálu jsme se začali zabývat transportní vrstvou síťového modelu TCP/IP. Přitom jsme si naznačili, že pro tuto vrstvu připadají v úvahu dva alternativní protokoly - TCP a UDP. Dnes se podrobněji zastavíme u jednoho z nich: protokolu UDP.
Nejprve si ale znovu připomeňme některé obecnější souvislosti, o kterých jsme se již zmínili. Zde jsme si řekli, že na rozdíl od referenčního modelu ISO/OSI považuje síťový model TCP/IP otázku zabezpečení spolehlivosti přenosů za věc koncových účastníků komunikace, a z tohoto důvodu zařazuje příslušné mechanismy pro zajištění spolehlivosti až do transportní vrstvy, zatímco na úrovni síťové vrstvy předpokládá pouze nespolehlivou službu nespojovaného charakteru (realizovanou protokolem IP). Řekli jsme si však také, že síťový model TCP/IP pamatuje i na to, že pro některé druhy aplikací nemusí být spolehlivé transportní služby výhodné. Proto jim nabízí jako alternativní možnost využívat i na úrovni transportní vrstvy služby stejné povahy a kvality, jakou mají přenosové služby na úrovni síťové vrstvy, zajišťované protokolem IP - tedy nespolehlivé přenosové služby nespojovaného charakteru.UDP jako jednoduchá "obálka" protokolu IP
Mechanismem, který entitám (procesům, úlohám, programům) aplikační vrstvy zpřístupňuje nespolehlivé a nespojované, zato ale rychlé a efektivní přenosové služby síťové vrstvy (protokolu IP), je právě protokol UDP (User Datagram Protocol). Můžeme si jej představit jako jednoduchou "obálku" nad protokolem IP, která nijak nemění povahu ani kvalitu jeho přenosových služeb, ale pouze je zprostředkovává své bezprostředně vyšší vrstvě. V podstatě jediné, co UDP zajišťuje navíc, je multiplexování a demultiplexování datagramů (viz minulý díl seriálu), tedy rozlišování různých příjemců, resp. odesilatelů v rámci téhož hostitelského počítače - podle čísla portu.
Odpovědnost přebírá aplikace
Každý aplikační program, který se rozhodne používat transportní služby protokolu UDP, tak na sebe přebírá odpovědnost za zajištění takové úrovně spolehlivosti přenosů, jakou sám potřebuje. Sám se také musí vyrovnávat i s dalšími důsledky, které vyplývají z nespolehlivého a nespojovaného charakteru přenosových služeb protokolu UDP - jako je např. zajišťování správného pořadí doručovaných datagramů, eliminace duplicitních datagramů apod.
Jak jsme si již uvedli v předchozích dílech, je volba nespolehlivých transportních služeb protokolu UDP determinována především charakterem aplikace a jeho požadavky na efektivitu přenosových služeb. Svou roli při rozhodování mezi nespolehlivými ale rychlejšími službami protokolu UDP a spolehlivými, zato ale pomalejšími transportními službami protokolu TCP však sehrává i prostředí, ve kterém jsou tyto transportní služby zajišťovány. Například v lokálních sítích, které jsou velmi rychlé a především relativně spolehlivé, může být protokol UDP pro mnohé aplikace velmi výhodný. Při přechodu do prostředí rozlehlých sítí, které jsou ve své podstatě mnohem méně spolehlivé, však může natolik narůst režie konkrétního aplikačního programu na zajištění potřebné spolehlivosti, že se pro ni stane protokol UDP méně výhodný, než "spolehlivý" protokol TCP, nebo se použití protokolu UDP stane dokonce zcela neúnosné.Formát UDP datagramu
Protokol UDP dostává od své bezprostředně vyšší vrstvy bloky dat, které se snaží vkládat celé do jednotlivých datagramů síťové vrstvy (IP datagramů). Proto se také těmto blokům na úrovni transportní vrstvy říká uživatelské datagramy (user datagrams), nebo též UDP datagramy (UDP datagrams).
Hlavičku (anglicky: header) UDP datagramu tvoří 4 položky v rozsahu 16 bitů, které po řadě vyjadřují číslo portu odesilatele a příjemce, délku UDP datagramu, a kontrolní součet.
Číslo portu příjemce (položka UDP DESTINATION PORT) je základní informací, podle které se protokol UDP na straně příjemce rozhoduje, komu má přijatý datagram doručit - přesněji: přes který port má přijatý datagram předat entitě aplikační vrstvy. Číslo portu odesilatele (v položce UDP SOURCE PORT) je nepovinné; vyplňuje se v případě, kdy je požadována odpověď (v opačném případě se tato položka zaplňuje nulami). Položka LENGTH vyjadřuje délku UDP datagramu, měřenou v oktetech (tj. osmicích bitů) - včetně vlastní hlavičky. Minimální délka UDP datagramu je proto 8, což je právě velikost hlavičky, s prázdnou datovou částí. Kontrolní součet (položka CHECKSUM) je počítán v rozsahu 16 bitů v aritmetice, která pro vyjádřená čísel se znaménkem využívá tzv. jedničkový doplněk (one's complement). Jednou ze zajímavých vlastností této nepříliš používané aritmetiky je skutečnost, že má dva možné způsoby znázornění nuly: tzv. kladnou nulu, tvořenou dvojkově samými nulami, a tzv. zápornou nulu, která má naopak všechny bity nastaveny na jedničku. V případě, že kontrolní součet vychází nulový, je použita právě tato druhá možnost, tedy tzv. záporná nula. Použití kontrolního součtu však není povinné. Jestliže se kontrolní součet nepoužije, je položka CHECKSUM vynulována - ovšem tzv. kladnou nulou, což je díky vlastnostem jedničkového doplňku možné odlišit od nulové hodnoty kontrolního součtu.Zvláštností protokolu UDP je skutečnost, že zmíněný kontrolní součet - je-li použit - není počítán z UDP datagramu), ale z větší datové struktury, která vznikne pomyslným připojením další hlavičky - tzv. pseudohlavičky (pseudo header) k vlastnímu datagramu. Pomyslným připojením v tom smyslu, že tato pseudohlavička není ve skutečnosti přenášena od odesilatele k příjemci, ale je brána v úvahu pouze pro výpočet kontrolního součtu.
V pseudohlavičce obsažena mj. IP adresa příjemce a odesilatele (která naopak ve vlastním UDP datagramu, resp. jeho hlavičce obsažena není). Protokol UDP na straně příjemce kontroluje bezchybovost všech přijatých datagramů novým výpočtem kontrolního součtu a jeho porovnáním s obsahem položky CHECKSUM. Uživatelský datagram sice přijme bez jeho pseudohlavičky, ale pro potřeby kontrolního součtu si ji protokol UDP znovu vytvoří a zahrne ji do nového výpočtu kontrolního součtu. Vzhledem k tomu, že pseudohlavička UDP datagramu obsahuje mj. i IP adresu příjemce, jde o mechanismus, který kromě poškozených datagramů umožňuje rozpoznat také datagramy, doručené na chybnou IP adresu (což z pouhého čísla portu, které je ve vlastním datagramu, nelze poznat), a následně je eliminovat. Zastavme se však ještě u právě naznačeného výpočtu kontrolního součtu. Podle něj musí protokol UDP u odesilatele již při sestavování UDP datagramu znát nejen IP adresu příjemce, ale i IP adresu odesilatele, neboť obě tyto adresy musí zahrnout do kontrolního součtu. IP adresu příjemce se protokol UDP dozví od aplikace, neboť právě ona určuje, komu jsou příslušná data určena. Pokud však jde o IP adresu odesilatele, nemusí být v silách protokolu UDP ji stanovit. Jde-li totiž o hostitelský počítač, který má více než jedno síťové rozhraní (tj. jde-li o tzv. multi-homed host, který je současně zapojen do více dílčích sítí, viz 46. díl seriálu), má odesilatel více různých IP adres (po jedné na každé síťové rozhraní, resp. pro každou dílčí síť). Rozhodnout, kudy bude příslušný datagram skutečně odeslán (tj. kterým síťovým rozhraním, resp. s jakou IP adresou odesilatele), je pak až v silách síťové vrstvy, resp. protokolu IP, který zajišťuje směrování. Protokol UDP si proto musí při sestavování uživatelského datagramu vyžádat pomoc protokolu IP, což ale poněkud narušuje standardní způsob interakce jednotlivých vrstev ve vrstevnatém modelu.