Vyšlo v týdeníku: | COMPUTERWORLD |
Číslo: | 15/93 |
Ročník: | 1993 |
Rubrika/kategorie: | Co je čím ... v počítačových sítích |
Díl: | 62 |
Lidé, kteří dostali za úkol vyvinout nové mechanismy pro zpřístupnění protokolů TCP/IP v prostředí BSD Unixu, si svůj původní úkol poněkud rozšířili: rozhodli se vytvořit takový prostředek, který by nebyl "šit na míru" jedné konkrétní soustavě protokolů, tj. TCP/IP, ale byl použitelný obecně pro jakoukoli soustavu protokolů, a dokonce i pro více soustav protokolů současně. V době, kdy si protokoly TCP/IP v prostředí Unixu teprve hledaly své místo, to bylo rozhodnutí vcelku logické. V současné době, kdy TCP/IP protokoly Unix zcela ovládly, není tato možnost příliš využívána. Do budoucna by se ale zmíněné rozhodnutí mohlo ukázat jako velmi prozíravé. Pokud se totiž referenční model ISO/OSI opravdu prosadí do života, nebo se alespoň stane skutečnou konkurencí pro síťový model TCP/IP, bude začlenění ISO protokolů do BSD Unixu velmi jednoduché.
Větší obecnost nově vytvořeného mechanismu, umožňující zpřístupnit aplikacím přenosové služby různých soustav protokolů, však není zcela zadarmo. Cenou za tuto větší obecnost je samozřejmě poněkud větší komplikovanost použití. Kdyby šlo o mechanismus, určený pouze pro protokoly TCP/IP, mohl by například vždy sám předpokládat, že kdykoli se mu zadá nějaká adresa, jde o tzv. IP adresu (viz 44. díl seriálu). Takto je nutné mu to explicitně sdělit.
Abychom si ale mohli ukázat, v čem toto zobecnění spočívá, musíme se ještě vrátit k souborům a způsobu práce s nimi.
Když se nějaký proces rozhodne pracovat s určitým souborem, musí jej nejprve otevřít. Vlastní otevření však zajišťuje operační systém, a proto si provedení potřebné operace (operace open) proces vyžádá na operačním systému. Konkrétní forma je taková, že proces použije tzv. systémové volání (system call), neboli spustí podprogram, který je součástí operačního systému. Svůj konkrétní požadavek (který soubor má být otevřen, jakým způsobem atd.) proces specifikuje prostřednictvím parametrů tohoto volání. Vlastní otevření souboru pak probíhá plně v režii operačního systému, který si za tímto účelem založí vhodnou datovou strukturu, a v ní si udržuje vše, co k práci se souborem potřebuje.
Proces, který si otevření souboru vyžádal, pak ještě musí mít k dispozici prostředek, pomocí kterého při všech následných operacích nad již otevřeným souborem (tj. operacích read, write a close atd.) určí, kterého souboru se požadované operace týkají. Nejlépe by se k tomuto účelu hodila zmíněná datová struktura, ale ta je zcela ve správě operačního systému, který ji aplikačním procesům nezveřejňuje. Přesto ale umožňuje aplikačním procesům odkazovat se na tuto strukturu, a to prostřednictvím nepřímého ukazatele (který je ve skutečnosti celým číslem bez znaménka, a lze si jej představit jako index do tabulky, obsahující ukazatele na zmíněné datové struktury). Operace open proto vrací jako svůj výsledek celé číslo (tzv. deskriptor souboru, file descriptor), a ten pak používají operace read, write a close k určení souboru, ze kterého se má číst, do kterého se má zapisovat, resp. který má být uzavřen.
Nyní si již můžeme snadno naznačit, co je podstatou nového mechanismu "socket interface". Samotný socket není nic jiného, než jiná varianta výše popsané datové struktury, ve které si operační systém uchovává různé údaje (tentokráte pro potřeby komunikace v síti). Socket opět není přímo přístupný, ale aplikační procesy se na něj mohou odkazovat přesně stejným způsobem, jako na zmíněnou datovou strukturu při práci se soubory - tedy nepřímo, prostřednictvím celého čísla. To se nyní označuje jako deskriptor socketu (socket descriptor), ale svým datovým typem je totožné s deskriptorem souboru (jde o celé číslo bez znaménka).
Stejný je také způsob práce se sockety - prostřednictvím systémových volání. Samotný repertoár systémových volání pro práci se sockety je však samozřejmě jiný, než pro práci se soubory. BSD Unix se však snaží zachovávat maximální možnou slučitelnost obou mechanismů, tak aby se lišily jen tam, kde je to skutečně nutné. Proto například umožňuje používat operace read a write jak pro čtení a zápis dat do souborů, tak i pro jejich vlastní přenos po síti prostřednictvím socketů. Za tímto účelem mj. vybírá celá čísla, která přiděluje jako deskriptory, z jediné množiny. Nemůže se tudíž stát, aby se číselná hodnota deskriptoru souboru a deskriptoru socketu rovnala.
Tím se vychází vstříc potřebám nejrůznějších procesů, které vystupují v roli serverů, potřebují si nechat vytvořit socket pro komunikaci se svými klienty, ale teprve následně se dozvídají, kteří klienti s nimi budou chtít komunikovat.
Žádost o vytvoření nového socketu, kterou aplikační proces předává operačnímu systému formou systémového volání (s příznačným názvem socket) však ve svých parametrech obsahuje údaj o tom, s jakou soustavou protokolů bude socket pracovat (což mj. definuje význam následně zadávaných adres), dále druh spojení (spolehlivé spojované či nespolehlivé nespojované, případně spojení na nižší úrovni, než je transportní), a také konkrétní protokol z příslušné rodiny protokolů, který bude přenos zajišťovat (což pamatuje na případ, kdy požadovaný druh spojení může být v rámci zvolené soustavy protokolů realizován více alternativními protokoly).
Zde je ovšem třeba si uvědomit, že porty jsou jednotným konstruktem v rámci celého síťového modelu TCP/IP, zatímco sockety jsou jen jedním z možných prostředků pro zpřístupnění transportních služeb aplikačním procesům (tím, který je používán v BSD Unixu). Jednotnost portů ve všech uzlech umožňuje jednotné adresování entit aplikační vrstvy, bez ohledu na to, jaký konkrétní mechanismus používají tyto entity pro přístup ke službám transportní vrstvy. Jsou-li tímto mechanismem sockety, existuje mezi nimi a porty jednoznačná korespondence: každý socket odpovídá jednomu portu, resp. je svázán s právě jedním portem.
Tato vazba mezi portem a socketem však není automatická. Přesněji: nevzniká při vytvoření socketu (systémovým voláním socket), ale musí být vytvořena až následně, na explicitní příkaz (systémovým voláním bind).
Volba lokálního portu, na který má být socket navázán, může být pro některé aoplikační procesy irrelevantní, a tyto procesy pak mohou nechat volbu konkrétního portu na operačním systému. Jinak je tomu ale u procesů, které vystupují v roli serverů, a své služby poskytují na tzv. dobře známých portech (se kterými předem počítají potenciální klienti těchto služeb), viz 55. díl seriálu.
Jak má ale postupovat proces, který sám komunikaci iniciovat nechce? Tedy například proces, který chce vystupovat v roli serveru, a chce přitom používat spojovaný charakter komunikace?
Také si musí nejprve nechat vytvořit potřebný socket (voláním socket), a pak jej navázat na vhodný lokální port (voláním bind). Pak ale musí uvést socket do takového stavu, který odpovídá pasivnímu otevření - tedy kdy socket (resp. na něj navázaný port) pouze pasivně čeká na přicházející žádosti o navázání spojení. Za tímto účelem je v BSD Unixu k dispozici další systémové volání listen, kterému se navíc jako parametr zadává, jak velkou frontu si má vytvořit pro přicházející volání či data.
Když je takto socket připraven přijímat žádosti o navázání spojení, musí začít čekat i samotný aplikační proces. K tomu má k dispozici další systémové volání accept.
![]() |
Celý postup komunikace spojovaného charakteru ze strany serveru i klienta ukazuje obr. 62.1., včetně zrušení socketu voláním close. V případě nespojované komunikace je celý postup poněkud jednodušší - na straně serveru pak odpadají volání listen a accept, která se týkají navazování spojení, a na straně klienta nepovinné volání connect.