InternetovΘ programovßnφ s WinSock (3)

 

Minule jsme vytvo°ili nßÜ prvnφ socket a dnes si koneΦn∞ p°edvedeme, k Φemu je u₧iteΦn². NauΦφme se navßzat spojenφ se serverem a p°enßÜet data pomocφ protokol∙ TCP i UDP.

 

Ustavenφ relace TCP

 

Proto₧e TCP je protokol spojovan², prvnφ, co musφme provΘst, je p°ipojenφ k serveru. Po p°ipojenφ je mo₧nΘ zasφlat serveru data a p°ijφmat odpov∞di bez opakovanΘho udßvßnφ cφlovΘ adresy. Ta je po p°ipojenφ pevn∞ urΦena a socket nenφ mo₧nΘ pou₧φvat pro komunikaci s jin²mi servery.

P°ipojenφ provedeme zavolßnφm funkce connect. Prvnφm parametrem je d°φve ·sp∞Ün∞ vytvo°en² socket typu SOCK_STREAM. Jako druh² parametr dosadφme ukazatel na sprßvn∞ vypln∞nou strukturu SOCKADDR_IN vΦetn∞ Φφsla portu. Proto₧e funkce connect poΦφtß i s jin²mi protokoly, ne₧ je TCP/IP, je na mφst∞ tohoto parametru oΦekßvßna obecn∞jÜφ struktura SOCKADDR. NßÜ ukazatel proto musφme sprßvn∞ p°etypovat. T°etφ a poslednφ parametr urΦuje velikost nßmi zadanΘ adresnφ struktury v bytech.

V p°φpad∞, ₧e je spojenφ ·sp∞Ün∞ navßzßno, funkce vrßtφ nulu, jinak vrßtφ k≤d SOCKET_ERROR.

Pro objasn∞nφ nßsleduje krßtk² v²pis:

 

SOCKET client_sock;

SOCKADDR_IN si;

...

/* vytvoreni socketu */

/* vyplneni adresy */

connect(client_sock, (SOCKADDR *) &si, sizeof si);

...

 

Odesφlßnφ a p°φjem dat

 

Kdy₧ jednou mßme socket p°ipojen² k serveru, m∙₧eme zaΦφt se samotnou komunikacφ. K odesφlßnφ dat slou₧φ funkce send a ke Φtenφ dat p°ijat²ch mßme funkci recv.

Funkce send mß Φty°i parametry. Prvnφm z nich je socket, jφm₧ chceme posφlat data. Tento socket musφ b²t ·sp∞Ün∞ vytvo°en² a p°ipojen². Jako druh² parametr se zadßvß ukazatel na buffer obsahujφcφ data k odeslßnφ. T°etφ parametr udßvß poΦet byt∙ z bufferu, kterΘ majφ b²t odeslßny. Poslednφ parametr specifikuje volby, kterΘ nebudeme pou₧φvat, proto sem budeme dosazovat nulu. Nßvratovou hodnotou je poΦet skuteΦn∞ odeslan²ch byt∙. Jestli₧e funkce sel₧e, je navrßcena hodnota SOCKET_ERROR.

Musφme si uv∞domit, ₧e funkce m∙₧e odeslat mΘn∞ dat, ne₧ jsme po₧adovali. V takovΘm p°φpad∞ musφme posunout ukazatel o poΦet poslan²ch byt∙, o stejnou hodnotu snφ₧it po₧adavek na mno₧stvφ dat, kterß zb²vß odeslat, a zavolat funkci send znovu s t∞mito nov²mi parametry. Toto je nutnΘ opakovat, dokud nejsou odbavena vÜechna naÜe data.

Nßsledujφcφ k≤d zajistφ odeslßnφ vÜech dat z bufferu urΦitΘ velikosti.

 

int offset;

char buf[256];

...

offset = 0;

while (offset < sizeof buf) {

á /* pokusime se odeslat zbytek bufferu */

á /* posuneme se o pocet skutecne odeslanych bytu */

á offset += send(sock, buf + offset, sizeof buf - offset, 0);

}

 

V tomto k≤du, stejn∞ jako v n∞kolika nßsledujφcφch, se dopouÜtφme p°φmo kriminßlnφho postupu. V ka₧dΘ aplikaci je nutno po Φtenφ a zßpisu nejd°φve zkontrolovat nßvratovou hodnotu, jestli nedoÜlo k chyb∞ nebo k ukonΦenφ relace, a pak je teprve mo₧nΘ ji pova₧ovat za poΦet p°enesen²ch byt∙. NaÜφm d∙vodem je snaha o Üet°enφ mφstem a koncentrace na vysv∞tlenφ samotnΘho p°enosu dat.

Uve∩me si jeÜt∞ jeden p°φklad, kter² je v praxi obvyklejÜφ. Tentokrßt mßme v bufferu pevnΘ velikosti ulo₧en nulou zakonΦen² textov² °et∞zec, kter² pot°ebujeme odeslat. UkonΦujφcφ nulu nikdy neodesφlßme, pokud to aplikaΦnφ protokol v²slovn∞ ne₧ßdß, jinak by prot∞jÜφ strana naÜφm zprßvßm nemusela v∙bec rozum∞t.

 

#include <string.h>

...

int len, offset;

char buf[256];

...

strcpy(buf, "Nejaka zprava, treba LIST /pub\r\n");

len = strlen(buf);

offset = 0;

while (offset < len) {

á offset += send(sock, buf + offset, len - offset, 0);

}

 

╚tenφ dat se provßdφ podobn²m zp∙sobem. Funkce recv mß op∞t Φty°i parametry s podobn²m v²znamem, jako tomu bylo v p°φpad∞ funkce send. Ukazatel p°edßvan² druh²m parametrem tentokrßt ukazuje na p°ipraven² buffer, do n∞ho₧ budou zapsßna p°ijatß data. T°etφ parametr urΦuje mno₧stvφ dat v bytech, kterΘ se do naÜeho bufferu vejde. Funkce vracφ poΦet p°ekopφrovan²ch byt∙, v p°φpad∞ chyby pak SOCKET_ERROR. PoΦet p°eΦten²ch byt∙ op∞t m∙₧e b²t menÜφ ne₧ zadanß velikost bufferu. Jestli₧e pot°ebujeme k dalÜφ prßci programu vφce dat, musφme volat funkci opakovan∞, podobn∞ jako tomu bylo v p°φpad∞ funkce send.

╚asto b²vajφ zprßvy odesφlanΘ klientem nebo serverem ukonΦeny specißlnφm znakem k tomu urΦen²m, nap°φklad koncem °ßdku. V takovΘm p°φpad∞ pot°ebujeme opakovan∞ volat recv, dokud v p°ijat²ch datech nenajdeme odd∞lovacφ znak. Nßsledujφcφ v²pis k≤du ukazuje, jak je mo₧nΘ p°eΦφst zprßvu ze serveru zakonΦenou znakem line feed (v C znßm²m jako new line).

 

#include <string.h>

...

int offset, last_offset, bytes;

/* do bufferu se musi vejit cela zprava */

char buf[2048];

...

offset = 0;

do {

á /* zapamatujeme si zacatek prijimaneho retezce */

á last_offset = offset;

á /* pokusime se precist co nejvice bytu */

á offset += recv(sock, buf + offset, sizeof buf - offset - 1, á áááá 0);

á /* ukoncime vznikly retezec nulou */

á buf[offset] = 0;

á /* skoncime, kdyz nalezneme znak LF */

} while (strchr(buf + last_offset, '\n') == NULL);

 

P°ijφmßme-li textovß data, s nimi₧ chceme pracovat pomocφ °et∞zcov²ch funkcφ, musφme sami doplnit ukonΦujφcφ nulu podobn∞ jako v p°edchozφm p°φklad∞. Funkce recv to za nßs neud∞lß, Φemu₧ se nesmφme divit, proto₧e tato funkce nemß tuÜenφ, jestli uklßdß data textovß nebo binßrnφ. Jestli₧e na to zapomeneme, je na sv∞t∞ dost nep°φjemnß chyba, proto₧e budeme p°edpoklßdat problΘm spφÜe v sφ¥ov²ch funkcφch ne₧ v naÜem vlastnφm poli.

 

Chovßnφ p°enosov²ch funkcφ

 

Jak u₧ bylo °eΦeno, funkce send a recv vracejφ jako sv∙j v²sledek poΦet skuteΦn∞ p°enesen²ch byt∙, kter² m∙₧e b²t ni₧Üφ ne₧ poΦet po₧adovan².

Nenφ-li mo₧nΘ odeslat data okam₧it∞, funkce send Φekß, dokud se jφ nepoda°φ odeslat alespo≥ Φßst dat. Teprve potom jejφ Φinnost skonΦφ a je vrßcen poΦet byt∙. To, co funkce send ve skuteΦnosti d∞lß, je zßpis dat do bufferu TCP. Samotn² p°enos p°es sφ¥ovΘ rozhranφ zajiÜ¥uje operaΦnφ systΘm asynchronn∞ mimo v∞domφ naÜeho programu. Jestli₧e p°i volßnφ funkce send jako poΦet byt∙ k odeslßnφ zadßme k nulu, funkce jednoduÜe vrßtφ nulu, nic neodeÜle, neohlßsφ chybu.

Chovßnφ funkce recv je trochu odliÜnΘ. Mohlo by se oΦekßvat, ₧e pokud nejsou k dispozici ₧ßdnß p°φchozφ data ze serveru, pak funkce vrßtφ nulu. SkuteΦnost je jinß. Funkce se pokusφ p°ekopφrovat co nejvφce byt∙ z bufferu TCP do bufferu naÜeho. Nejsou-li ₧ßdnß data k dispozici, funkce Φekß, dokud n∞jakß nep°ijdou, a teprve po jejich zkopφrovßnφ ukonΦφ svou Φinnost. Jestli₧e tedy v programu zavolßme recv v okam₧iku, kdy server nemß v ·myslu odeslat ₧ßdnß dalÜφ data, program nav₧dy zatuhne.

Funkce recv vrßtφ nulu v p°φpad∞, ₧e prot∞jÜφ poΦφtaΦ zruÜil spojenφ TCP korektnφm zp∙sobem.

Kdy₧ dojde k nestandardnφmu v²padku spojenφ, funkce send i recv vracejφ zßporn² chybov² k≤d SOCKET_ERROR.

Existuje zp∙sob, jak jednoduÜe zjistit, jestli jsou na socketu n∞jakß p°φchozφ data. K tomuto ·Φelu m∙₧eme pou₧φt funkci ioctlsocket, kterß slou₧φ i k n∞kter²m dalÜφm mΘn∞ obvykl²m operacφm se socketem. Za prvnφ parametr dosadφme pat°iΦn² socket, za druh² konstantu FIONREAD urΦujφcφ druh operace - zjiÜt∞nφ dostupnΘho mno₧stvφ p°φchozφch dat. T°etφm parametrem musφ b²t ukazatel na 32bitovou celoΦφselnou prom∞nnou, do nφ₧ bude zapsßn poΦet byt∙ p°φtomn²ch v bufferu, kterΘ mohou b²t zφskßny jednφm volßnφm funkce recv. Funkce vrßtφ nulu nebo SOCKET_ERROR, jak u₧ jsme zvyklφ.

 

long bytes;

...

ioctlsocket(sock, FIONREAD, &bytes);

if (bytes > 0)

á recv(sock, buf, sizeof buf, 0);

...

 

SkuteΦnost, ₧e funkce recv a send mohou Φekat a blokovat zbytek programu, m∙₧e b²t nep°φjemnß. Ze zatφm probran²ch funkcφ se podobn²m zp∙sobem chovajφ takΘ funkce gethosbyname a connect. Ob∞ nejd°φve Φekajφ na odpov∞∩ vzdßlenΘho poΦφtaΦe, a potom teprve vracejφ svΘ nßvratovΘ hodnoty. Proto i tyto funkce mohou zp∙sobit doΦasnΘ "zaseknutφ" programu. To je tolerovatelnΘ v programech pracujφcφch v dßvkovΘm re₧imu nebo ovlßdan²ch z p°φkazovΘ °ßdky. V normßlnφm udßlostmi °φzenΘm programu s grafick²m u₧ivatelsk²m rozhranφm by takovΘ chovßnφ bylo nevhodnΘ a takov² program by urΦit∞ d∙v∞ru nezφskal. V t∞chto programech se pou₧φvajφ sockety v tzv. neblokujφcφm re₧imu, p°φpadn∞ blokujφcφ funkce b∞₧φcφ v samostatnΘm vlßkn∞. My zatφm z∙staneme v blokujφcφm re₧imu, kter² je jednoduÜÜφ a k vysv∞tlovßnφ princip∙ prßce se sockety vhodn∞jÜφ. K funkcφm neblokujφcφm se vrßtφme pozd∞ji.

 

ZruÜenφ relace TCP

 

PotΘ, co jsme ukonΦili komunikaci se vzdßlen²m poΦφtaΦem, je nutnΘ se sprßvn∞ odpojit. Spojenφ TCP je obousm∞rnΘ, a proto existuje mo₧nost uzav°φt spojenφ v ka₧dΘm sm∞ru zvlßÜ¥. K tomu pou₧φvßme funkci shutdown. Jejφm prvnφm parametrem je samoz°ejm∞ socket, kter² pot°ebujeme odpojit. Druh² parametr udßvß, ve kterΘm sm∞ru se mß spojenφ ukonΦit. Konstanta 1 znamenß, ₧e ze socketu jeÜt∞ m∙₧eme Φφst, ale odesφlßnφ dalÜφch dat u₧ je nemo₧nΘ. Aplikace na prot∞jÜφ stran∞ spojenφ obdr₧φ tzv. paket FIN, kter² oznamuje, ₧e tato polovina spojenφ je uzav°ena. Konstanta 0 naopak zp∙sobφ ukonΦenφ p°φjmu dat a hodnota 2 uzav°enφ v obou sm∞rech.

V praxi se pou₧φvß tento postup:

            Po odeslßnφ vÜech dat zavolßme funkci shutdown s volbou 1, Φφm₧ oznßmφme vzdßlenΘmu poΦφtaΦi, ₧e z naÜφ strany se u₧ dat nedoΦkß.

            Pomocφ funkce recv p°eΦteme vÜechna data, kterß nßm server jeÜt∞ poÜle.

            Server zav°e druhou polovinu spojenφ, co₧ poznßme podle toho, ₧e recv vrßtφ nulu (nebo chybov² k≤d, p°eruÜφ-li se spojenφ nestandardnφm zp∙sobem).

            Teprve te∩ zruÜφme socket pomocφ funkce closesocket.

V n∞kter²ch protokolech, nap°φklad v p°φpad∞ datovΘho spojenφ FTP, ukonΦuje relaci nejd°φve server. V takovΘm p°φpad∞ po p°eΦtenφ vÜech dat zjistφme, ₧e server zav°el svou odesφlajφcφ stranu spojenφ. TotΘ₧ ud∞lßme my pomocφ funkce shutdown a m∙₧eme okam₧it∞ zav°φt socket pomocφ closesocket.

N∞kdy se jedna polovina spojenφ uzavφrß pom∞rn∞ brzy po navßzßnφ spojenφ a ke komunikaci se pou₧φvß jen polovina druhß. Nap°φklad WWW prohlφ₧eΦ poÜle serveru pom∞rn∞ krßtk² po₧adavek HTTP, zav°e svou odesφlacφ stranu socketu, a pak u₧ jen p°ijφmß data.

Program by m∞l v₧dy zavφrat jen svou odesφlacφ polovinu spojenφ a nem∞l by pou₧φvat jinΘ, nßsilnΘ postupy.

 

Stahovßnφ strßnek WWW

 

V tuto chvφli mßme probrßno pom∞rn∞ dost lßtky, proto si zaslou₧φme trochu efektn∞jÜφ p°φklad. Bude jφm program pro stahovßnφ WWW strßnek a jejich uklßdßnφ na disk. Program (pracuje v konzolovΘm re₧imu) se nejd°φve zeptß na adresu serveru (nap°. www.chip.cz), pak na cestu k dokumentu v rßmci serveru (v nejjednoduÜÜφm p°φpad∞ /) a nakonec na jmΘno souboru, do kterΘho nßsledn∞ ulo₧φ sta₧enou strßnku. V zßjmu jednoduchosti program nepracuje s adresami URL a jsou ignorovßny vÜechny mo₧nΘ chyby s v²jimkou neexistujφcφ adresy.

Sta₧enφ strßnky mß na starosti protokol HTTP. V nßmi pou₧itΘ verzi HTTP 0.9 mß po₧adavek na strßnku tvar GET /cesta<CR><LF>. Server jako odpov∞∩ odeÜle obsah po₧adovanΘho dokumentu. V pokroΦilejÜφch verzφch je p°φmo v po₧adavku uvedena verze protokolu a komunikace je bohatÜφ o tzv. hlaviΦky, pomocφ nich₧ si klient a server vym∞≥ujφ r∙znΘ informace.

Nßsleduje kompletnφ v²pis programu.

 

#include <stdio.h>

#include <string.h>

#include <winsock.h>

 

int main(void)

{

á WSADATA WSAData;

á SOCKADDR_IN si;

á SOCKET sock;

á unsigned long ip_addr;

á char buf[2048];

á int len, offset;

á FILE *fw;

 

á WSAStartup(0x0101, &WSAData);

á printf("Zadejte adresu serveru: ");

á gets(buf);

 

á /* preklad adresy */

á ip_addr = inet_addr(buf);

á if (ip_addr == INADDR_NONE) {

ááá HOSTENT *phe = gethostbyname(buf);

ááá

ááá if (phe != NULL)

ááááá ip_addr = *(unsigned long *) (phe->h_addr);

á }

á if (ip_addr == INADDR_NONE) {

ááá printf("Server nenalezen.\r\n");

ááá return 0;

á }

 

á /* pripojeni k serveru HTTP */

á si.sin_familyáááááá = AF_INET;

á si.sin_addr.s_addrá = ip_addr;

á si.sin_portáááááááá = htons(80);

 

á sock = socket(AF_INET, SOCK_STREAM, 0);

á connect(sock, (SOCKADDR *) &si, sizeof si);

 

á /* sestaveni a odeslani pozadavku */

á strcpy(buf, "GET ");

á printf("Zadejte cestu zacinajici lomitkem: ");

á gets(buf + strlen(buf));

á strcat(buf, "\r\n");

 

á len = strlen(buf);

á offset = 0;

á while (offset < len)

ááá offset += send(sock, buf + offset, len - offset, 0);

á shutdown(sock, 1);

 

á /* prijem a ulozeni dokumentu */

á printf("Zadejte jmeno mistniho souboru: ");

á gets(buf);

á fw = fopen(buf, "w");

á /* cteme, dokud se server neodpoji */

á while ((len = recv(sock, buf, sizeof buf, 0)) > 0)ááá

ááá fwrite(buf, 1, len, fw);

á fclose(fw);

á

á closesocket(sock);

á WSACleanup();

á return 0;

}

 

Klient nad UDP

 

Prßce se socketem protokolu UDP je odliÜnß a o n∞co jednoduÜÜφ, ne₧ tomu bylo v p°φpad∞ protokolu TCP. Nenφ ustavovßno ₧ßdnΘ spojenφ, a proto odpadß volßnφ funkcφ connect a shutdown. Po vytvo°enφ socketu typu SOCK_DGRAM je mo₧nΘ okam₧it∞ posφlat a p°ijφmat data. K tomu slou₧φ funkce sendto, kterß odesφlß datagram na uvedenou adresu a funkce recvfrom, kterß p°eΦte p°ijat² datagram a zßrove≥ ulo₧φ adresu, ze kterΘ p°iÜel. Jedin² socket tedy m∙₧eme pou₧φvat pro komunikaci s n∞kolika poΦφtaΦi nebo aplikacemi. Na podrobnosti p°enosu datagram∙ se podφvßme dßle.

MΘn∞ obvykl²m, ale takΘ mo₧n²m postupem je svßzßnφ socketu s jednou adresou pomocφ funkce connect. Po zavolßnφ tΘto funkce nedojde ustavenφ ₧ßdnΘho spojenφ, pouze k omezenφ socketu na jedinou vzdßlenou adresu. P°enos datagram∙ se pak provßdφ pomocφ nßm u₧ znßm²ch funkcφ send a recv, u kter²ch se neuvßdφ ₧ßdnß adresa. Datagramy p°ijatΘ z jin²ch adres jsou zahazovßny. Zm∞nit adresu, ke kterΘ je socket "p°ipojen" je mo₧nΘ opakovan²m volßnφm funkce connect. Jestli₧e chceme omezenφ zruÜit, zavolßme connect se strukturou typu SOCKADDR_IN obsahujφcφ adresu IP 0.0.0.0. PotΘ m∙₧eme socket UDP pou₧φvat zase standardnφm zp∙sobem.

Po skonΦenφ prßce se socketem jej jednoduÜe zruÜφme pomocφ volßnφ closesocket. Nikdy nevolßme funkci shutdown, ani v p°φpad∞, ₧e byl socket "p°ipojen" pomocφ funkce connect.

 

P°enos datagram∙

 

Funkce sendto mß prvnφ Φty°i parametry podobnΘ jako funkce send. Jsou to socket, ukazatel na buffer, velikost datagramu v bytech a volby. Pßt²m parametrem je ukazatel na cφlovou adresu, kterß mß obdr₧et datagram. Ukazatel na vypln∞nou strukturu SOCKADDR_IN musφme op∞t p°etypovat na typ SOCKADDR*. Poslednφm parametrem je velikost naÜφ adresnφ struktury v bytech.

 

#include <string.h>

...

SOCKET sock;

SOCKADDR_IN si;

char buf[128]

...

sock = socket(AF_INET, SOCK_DGRAM, 0);

/* vyplneni adresy si */

strcpy(buf, "Servere, toto je muj datagram!");

sendto(sock, buf, strlen(buf), 0, (SOCKADDR *) si, sizeof si);

...

 

Funkce sendto vracφ poΦet odeslan²ch byt∙, v p°φpad∞ selhßnφ SOCKET_ERROR. Velikost datagramu nesmφ b²t p°φliÜ velkß, jinak se zvyÜuje nebezpeΦφ jeho ztrßty po cest∞, p°φpadn∞ jeho odeslßnφ nemusφ b²t v∙bec mo₧nΘ. JednotlivΘ datagramy by m∞ly b²t velkΘ °ßdov∞ do stovek byt∙, nad 512 byt∙ obvykle dochßzφ k fragmentaci. Hornφm limitem, ke kterΘmu u₧ by se aplikace nem∞ly p°φliÜ p°ibli₧ovat, je 8 KB pro jeden datagram. Funkce sendto neohlßsφ ₧ßdnou chybu, jestli₧e byl datagram ·sp∞Ün∞ odeslßn, ale nebyl doruΦen k cφli.

Funkce recvfrom Φte data jednoho p°ijatΘho datagramu. Parametry jsou op∞t analogickΘ: socket, buffer pro p°φjem, maximßlnφ poΦet byt∙, volby. Pßt² parametr je ukazatel na strukturu SOCKADDR_IN, do kterΘ mß b²t ulo₧ena adresa, ze kterΘ datagram p°iÜel. Jednß se o parametr v²stupnφ, adresa je vypln∞na a₧ funkcφ recvfrom. èest² parametr se liÜφ. Je to ukazatel na celoΦφselnou prom∞nnou obsahujφcφ velikost bufferu pro adresu. P°ed volßnφm musφ b²t v tΘto prom∞nnΘ ulo₧en poΦet byt∙ pro ulo₧enφ adresy, funkce toto Φφslo zm∞nφ na skuteΦnou velikost ulo₧enΘ adresnφ struktury. Jestli₧e nßs adresa odesφlatele nezajφmß, m∙₧eme dosadit za poslednφ dva parametry NULL.

Funkce vracφ poΦet byt∙ z p°eΦtenΘho datagramu. Jestli₧e nßÜ buffer nenφ dost velk², aby se do n∞j cel² datagram veÜel, je zbytek datagramu zahozen a funkce navφc vrßtφ chybov² k≤d. Ka₧dΘ p°φÜtφ volßnφ recvfrom Φte v₧dy nov² datagram. Velikost prvnφho p°ijatΘho datagramu, kter² Φekß na p°eΦtenφ, m∙₧eme urΦit pomocφ funkce ioctlsocket s parametrem FIONREAD, kterou jsme u₧ zmφnili u proudov²ch socket∙ TCP. LepÜφ je ale znßt pevnou maximßlnφ velikost datagramu, kter² m∙₧eme obdr₧et, a Φφst v₧dy do bufferu s touto velikostφ.

 

SOCKET sock;

char buf[512];

int bytes;

...

/* vytvoreni socketu */

/* komunikace se serverem */

bytes = recvfrom(sock, buf, sizeof buf, 0, NULL, NULL);

/* v bufferu mame datagram, v promenne bytes jeho delku */

 

Funkce sendto a recvfrom Φekajφ, dokud nenφ cel² datagram p°enesen, a proto stejn∞ jako send a recv blokujφ dalÜφ Φinnost programu.

 

Zßv∞r

 

Te∩ u₧ vφme, ₧e funkΦnφ internetov² klient nemusφ b²t zase tak slo₧it². P°φÜt∞ se podφvßme na Φinnosti typickΘ pro serverovΘ aplikace a dalÜφ d∙le₧itΘ oblasti.