10. Prßce se sokety

V tΘto kapitole se zaΦneme zab²vat vytvß°enφm Internetovsk²ch a Intranetovsk²ch aplikacφ a distribuovan²ch aplikacφ. Nejd°φve se budeme zab²vat sokety.
Komponenty soket∙ umo╛≥ujφ vytvß°et aplikace, kterΘ mohou komunikovat s ostatnφmi systΘmy pomocφ TCP/IP a podobn²ch protokol∙. Pomocφ soket∙ m∙╛eme Φφst a zapisovat prost°ednictvφm p°ipojenφ na dal╣φ poΦφtaΦ a to bez nutnosti znalostφ aktußlnφho sφ╗ovΘho software. Sokety poskytujφ p°ipojenφ zalo╛enΘ na protokolu TCP/IP, ale jsou takΘ urΦeny pro prßci s podobn²mi protokoly, jako je Xerox Network System (XNS), DECnet firmy Digital nebo IPX/SPX firmy Novell.
C++ Builder umo╛≥uje zapisovat sφ╗ovΘ servery nebo klientskΘ aplikace, kterΘ Φtou z nebo zapisujφ na ostatnφ systΘmy. Aplikace serveru nebo klienta je obvykle vyhrazena k jednΘ slu╛b∞ jako je Hypertext Transfer Protocol (HTTP) nebo File Transfer Protocol (FTP). Pomocφ soket∙ serveru, aplikace poskytujφcφ jednu z t∞chto slu╛eb, se m∙╛e spojit s klientskou aplikacφ, kterß chce pou╛φvat tuto slu╛bu. KlientskΘ sokety umo╛≥ujφ aplikaci pou╛φvajφcφ jednu z t∞chto slu╛eb, spojenφ se serverovou aplikacφ, kterß slu╛bu poskytuje.
K zßpisu aplikacφ pou╛φvajφcφch sokety, musφme pochopit:

Implementovßnφ slu╛eb

Sokety poskytujφ jßdro pot°ebnΘ k zßpisu sφ╗ov²ch server∙ a klientsk²ch aplikacφ. Mnoho slu╛eb, jako je HTTP nebo FTP je dob°e dostupn²ch. N∞kdy jsou slu╛by zabudovanΘ do operaΦnφho systΘmu a tedy nenφ nutnΘ zapisovat svΘ vlastnφ. NicmΘn∞, kdy╛ po╛adujeme lep╣φ °φzenφ ne╛ poskytuje implementovanß slu╛ba, t∞sn∞j╣φ integraci mezi na╣φ aplikacφ a sφ╗ovou komunikacφ nebo kdy╛ po╛adovanß slu╛ba nenφ dostupnß, pak m∙╛eme chtφt vytvo°it svoji vlastnφ serverovou nebo klientskou aplikaci. Nap°. kdy╛ pracujeme s distribuovanou datovou mno╛inou, m∙╛eme chtφt zapsat komunikaΦnφ vrstvu s databßzemi na ostatnφch systΘmech.
K implementaci a pou╛φvßnφ slu╛eb realizovan²ch sokety se musφme seznßmit s:

Protokoly slu╛eb

D°φve ne╛ m∙╛eme zapisovat aplikaci sφ╗ovΘho serveru nebo klienta, musφme pochopit slu╛by, kterΘ na╣e aplikace bude poskytovat nebo pou╛φvat. Mnoho slu╛eb mß standardnφ protokoly, kterΘ na╣e sφ╗ovß aplikace m∙╛e vyu╛φvat. Pokud zapisujeme sφ╗ovou aplikaci pro standardnφ slu╛bu, jako je HTTP nebo FTP, musφme nejprve pochopit protokoly pou╛itΘ pro komunikaci s ostatnφmi systΘmy. Musφme si prohlΘdnout dokumentaci slu╛by, kterou chceme pou╛φvat.
Pokud poskytujeme novou slu╛bu pro aplikaci, kterß komunikuje s ostatnφmi systΘmy, pak prvnφm krokem je navr╛enφ komunikaΦnφho protokolu pro server i klienta tΘto slu╛by. JakΘ zprßvy jsou zasφlßny? Jak jsou tyto zprßvy koordinovßny? Jak jsou informace zak≤dovßny?
╚asto na╣e aplikace sφ╗ovΘho serveru nebo klienta poskytuje vrstvu mezi sφ╗ov²m softwarem a aplikacφ, kterß pou╛φvß slu╛by. Nap°. HTTP server je mezi aplikacφ Web serveru a Internetem, kter² poskytuje p°ipojenφ a reaguje na zprßvy HTTP.
Sokety poskytujφ rozhranφ mezi na╣im sφ╗ov²m serverem nebo klientskou aplikacφ a sφ╗ov²m software. Musφ poskytnout rozhranφ mezi na╣φ aplikacφ a aplikacφ, kterß ji pou╛φvß. M∙╛eme pou╛φt standardnφ slu╛bu API (jako je ISAPI) nebo m∙╛eme navrhnout a zve°ejnit svΘ vlastnφ API.
Slu╛by a porty
V∞t╣ina standardnφch slu╛eb je spojenß (konvencφ) se specifick²m Φφslem portu. Kdy╛ implementujeme slu╛bu, pak m∙╛eme pova╛ovat Φφslo portu jako Φφseln² k≤d slu╛by.
Jestli╛e implementujeme standardnφ slu╛bu, objekty soket∙ Windows poskytujφ metody pro nalezenφ Φφsla portu pro slu╛bu. Pokud poskytujeme novou slu╛bu, pak m∙╛eme specifikovat p°i°azenΘ Φφslo portu v souboru SERVICES na poΦφtaΦi s Windows 95 nebo NT. Vφce informacφ o nastavovßnφ souboru SERVICES nalezneme v dokumentaci Soket∙ Windows.

Typy soketov²ch p°ipojenφ

Soketovß p°ipojenφ m∙╛eme rozd∞lit na t°i zßkladnφ typy, kterΘ urΦujφ, jak p°ipojenφ bude inicializovßno a k Φemu se p°ipojujeme. Jsou to: Pouze p°ipojenφ na klientsk² soket je kompletovßno, jinak serverovΘ p°ipojenφ je nerozeznatelnΘ od klientskΘho p°ipojenφ. Oba koncovΘ body majφ stejnΘ mo╛nosti a zφskßvajφ stejnΘ typy udßlostφ. Naslouchacφ p°ipojenφ se zßsadn∞ li╣φ, mß pouze jeden koncov² bod.

KlientskΘ p°ipojenφ

KlientskΘ p°ipojenφ p°ipojuje klientsk² soket na lokßlnφm systΘmu k serverovΘmu soketu na vzdßlenΘm systΘmu. Klientskß p°ipojenφ jsou inicializovßna klientsk²m soketem. Klientsk² soket musφ popisovat serverov² soket, ke kterΘmu se chceme p°ipojit. Klientsk² soket pak hledß serverov² soket a kdy╛ server nalezne vy╛aduje p°ipojenφ. Serverov² soket udr╛uje frontu klientsk²ch po╛adavk∙ a kompletuje p°ipojenφ. Kdy╛ serverov² soket akceptuje klientskΘ p°ipojenφ, pak serverov² soket, ke kterΘmu se p°ipojujeme zasφlß sv∙j pln² popis klientskΘmu soketu a p°ipojenφ je klientem kompletovßno.

Naslouchacφ p°ipojenφ

ServerovΘ sokety nelokalizujφ klienty. Jsou pasivnφ formou "poloviny p°ipojenφ" kterß naslouchß klientsk²m po╛adavk∙m. ServerovΘ sokety p°i°azujφ frontu ke sv²m naslouchacφm p°ipojenφm; fronta zaznamenßvß po╛adavky klient∙ na p°ipojenφ jak p°ichßzejφ. Kdy╛ serverov² soket akceptuje po╛adavek na klientskΘ p°ipojenφ, provedeto to formou novΘho soketu pro p°ipojenφ klienta a naslouchacφ p°ipojenφ z∙stßvß otev°eno pro akceptovßnφ ostatnφch klientsk²ch po╛adavk∙.

SeverovΘ p°ipojenφ

ServerovΘ p°ipojenφ je formovßno serverov²mi sokety, kdy╛ naslouchacφ soket akceptuje klientsk² po╛adavek. Popis serverovΘho soketu, kter² kompletuje p°ipojenφ ke klientu je zaslßn klientu, kdy╛ server p°ipojenφ akceptuje. P°ipojenφ je z°φzeno, kdy╛ klientsk² soket p°ijme tento popis a kompletuje p°ipojenφ.

Popisovßnφ soket∙

Sokety umo╛≥ujφ na╣i sφ╗ovΘ aplikaci komunikovat s ostatnφmi systΘmy v sφti. Na ka╛d² soket se m∙╛eme dφvat jako na koncov² bod sφ╗ovΘho propojenφ. Mß adresu, kterß specifikuje: Pln² popis soketovΘho propojenφ, musφ poskytnout adresy soket∙ na obou koncφch p°ipojenφ. M∙╛eme popsat adresu ka╛dΘho soketovΘho koncovΘho bodu p°edßnφm IP adresy nebo jmΘna hostitele a Φφsla portu.
D°φve ne╛ m∙╛eme z°φdit propojenφ soket∙, musφme pln∞ popsat sokety tvo°φcφ jeho koncovΘ body. N∞kterΘ informace jsou dostupnΘ ze systΘmu, na kterΘm je na╣e aplikace spu╣t∞na. Nap°. nemusφme zadßvat lokßlnφ IP adresu klientskΘho soketu nebo╗ tato informace je zjistitelnß z operaΦnφho systΘmu.
Informace, kterΘ musφme poskytnout zßvisφ na typu soketu se kter²m pracujeme. Klientsk² soket musφ popsat server, ke kterΘmu se chceme p°ipojit. Naslouchacφ soket serveru musφ popsat port, kter² reprezentuje poskytovanou slu╛bu.

Popisovßnφ hostitele

Hostitel je systΘm, spou╣t∞jφcφ aplikaci, kterß obsahuje soket. Hostitele pro soket m∙╛eme popsat jeho IP adresou, co╛ je °et∞zec Φty° Φφseln²ch hodnot (slabik) v teΦkovΘm zßpisu Internetu, jako je
123.197.1.2
Jeden systΘm m∙╛e b²t identifikovßn vφce ne╛ jednou IP adresou.
IP adresy jsou obtφ╛n∞ zapamatovatelnΘ a jsou zdrojem chyb. Alternativou je pou╛itφ jmΘna hostitele. JmΘno hostitele je p°ezdφvka pro IP adresu, kterou Φasto vidφme v URL (Uniform Resource Locators). Je to °et∞zec obsahujφcφ jmΘno domΘny a slu╛by, nap°.
http://www.wSite.Com
V Internetu poskytujeme jmΘno hostitele pro IP adresu systΘmu na Internetu. Na poΦφtaΦφch s operaΦnφm systΘmem Windows 95/98/NT, pokud jmΘno hostitele nenφ dostupnΘ, pak jej m∙╛eme vytvo°it pro na╣i lokßlnφ adresu zadßnφm jmΘna do souboru HOSTS. Vφce informacφ o souboru HOSTS nalezneme v dokumentaci Soket∙ Windows.
ServerovΘ sokety nepot°ebujφ specifikovat hostitele. Lokßlnφ IP adresa m∙╛e b²t p°eΦtena ze systΘmu. Pokud systΘm mß vφce ne╛ jednu IP adresu, pak serverovΘ sokety naslouchajφcφ klientsk²m po╛adavk∙m naslouchajφ na v╣ech IP adresßch souΦasn∞. Kdy╛ serverov² soket akceptuje p°ipojenφ, pak klientsk² soket poskytne vzdßlenou IP adresu. Klientsk² soket musφ specifikovat vzdßlenΘho hostitele poskytnutφm jmΘna hostitele nebo IP adresy.
V∞t╣ina aplikacφ pou╛φvß jmΘno hostitele pro specifikaci systΘmu. JmΘno hostitele je snadn∞ji zapamatovatelnΘ a snadn∞ji se testuje na typografickΘ chyby. Dßle server m∙╛e zm∞nit systΘm nebo IP adresu, kterß je p°i°azena k jistΘmu jmΘnu hostitele. Pou╛itφm jmΘna hostitele m∙╛e klientsk² soket nalΘzt abstraktnφ mφsto reprezentovanΘ jmΘnem hostitele i kdy╛ jeho IP adresa se zm∞nφ.
Pokud jmΘno hostitele je neznßmΘ, pak klientsk² soket musφ specifikovat systΘm serveru pomocφ jeho IP adresy. Specifikace serverovΘho systΘmu pomocφ IP adresy je rychlej╣φ. Kdy╛ poskytneme jmΘno hostitele, pak soket musφ hledat IP adresu p°i°azenou k tomuto jmΘnu hostitele, d°φve ne╛ m∙╛e lokalizovat systΘm serveru.

Pou╛φvßnφ port∙

I kdy╛ IP adresa poskytuje dostatek informacφ k nalezenφ systΘmu na druhΘm konci soketovΘho p°ipojenφ, musφme takΘ zadat Φφslo portu na tomto systΘmu. Bez Φφsel port∙ by systΘm mohl pracovat pouze s jednφm p°ipojenφm. ╚φsla port∙ jsou jednoznaΦnΘ identifikßtory, kterΘ umo╛≥ujφ jednomu systΘmu hostit souΦasn∞ vφce p°ipojenφ, p°i°azenφm ka╛dΘmu p°ipojenφ samostatnΘho Φφsla portu.
Z jednoho pohledu, Φφsla port∙ jsou ΦφselnΘ k≤dy pro slu╛by implementovanΘ sφ╗ovou aplikacφ. To je konvence, kterß umo╛≥uje naslouchacφm serverov²m p°ipojenφm b²t dostupn²mi na pevn²ch Φφslech port∙ a tedy mohou b²t hledßny klientsk²mi sokety. ServerovΘ sokety naslouchajφ na portu Φφsla p°i°azenΘho ke slu╛b∞, kterou poskytuje. Kdy╛ akceptujφ p°ipojenφ na klientsk² soket, pak vytvß°φ samostatnΘ soketovΘ p°ipojenφ, kterΘ pou╛φvß jinΘ Φφslo portu. Tφmto zp∙sobem naslouchacφ p°ipojenφ m∙╛e stßle poslouchat na portu Φφsla p°i°azenΘho ke slu╛b∞.
KlientskΘ sokety pou╛φvajφ volnß lokßlnφ Φφsla port∙, kterß nejsou pou╛φvßny ostatnφmi sokety. Specifikujφ Φφslo portu serverovΘho soketu, ke kterΘmu se cht∞jφ p°ipojit a tak nalΘzt serverovou aplikaci. ╚asto toto Φφslo portu je specifikovßno nep°φmo, jmΘnem po╛adovanΘ slu╛by.

Pou╛φvßnφ komponent soket∙

C++ Builder poskytuje (na strßnce Internet Palety komponent) dv∞ komponenty soket∙, klientsk² soket a serverov² soket, kterΘ umo╛≥ujφ na╣im sφ╗ov²m aplikacφm p°ipojenφ na jin² poΦφtaΦ a kterΘ umo╛≥ujφ Φφst a zapisovat informace pomocφ tohoto propojenφ. Ke ka╛dΘ z t∞chto komponent je p°i°azen objekt soketu Windows, kter² reprezentuje koncov² bod aktußlnφho propojenφ soket∙. Komponenta soketu pou╛φvß objekty soket∙ Windows k zaobalenφ volßnφ API soketu Windows a tak na╣e aplikace se nemusφ zab²vat detaily z°izovßnφ p°ipojenφ nebo sprßvou zprßv soketu.
Pokud chceme pracovat s volßnφm API soketu Windows nebo p°izp∙sobit detaily propojenφ, pak m∙╛eme pou╛φt vlastnosti, udßlosti a metody objektu soketu Windows.

Pou╛φvßnφ klientsk²ch soket∙

P°idßnφm komponenty klientskΘho soketu (TClientSocket) na nß╣ formulß° nebo datov² modul zapojφme na╣i aplikaci do klienta TCP/IP. KlientskΘ sokety umo╛≥ujφ specifikovat serverov² soket, ke kterΘmu se chceme p°ipojit a slu╛bu, kterou po╛adujeme od serveru. Kdy╛ ji╛ mßme popsanΘ po╛adovanΘ p°ipojenφ, pak m∙╛eme pou╛φt komponentu soketu klienta ke kompletovßnφ p°ipojenφ na server.
Ka╛dß komponenta klientskΘho soketu pou╛φvß jeden objekt soketu Windows (TClientWinSocket) k reprezentaci klientskΘho koncovΘho bodu v p°ipojenφ.
KlientskΘ sokety pou╛φvßme ke:
Specifikace ╛ßdanΘho serveru
Komponenta klientskΘho soketu mß °adu vlastnostφ, kterΘ umo╛≥ujφ specifikovat systΘm serveru a port, ke kterΘmu se chceme p°ipojit. SystΘm serveru m∙╛eme specifikovat jeho jmΘnem hostitele pomocφ vlastnosti Host. Pokud neznßme jmΘno hostitele, nebo pokud chceme urychlit lokalizaci serveru, pak m∙╛eme specifikovat teΦkovou IP adresu systΘmu serveru pomocφ vlastnosti Address. Musφme specifikovat jmΘno hostitele nebo IP adresu. Pokud specifikujeme obojφ, pak komponenta pou╛ije jmΘno hostitele.
Mimo systΘmu serveru, musφme specifikovat port na systΘmu serveru, ke kterΘmu se nß╣ klientsk² soket chce p°ipojit. M∙╛eme chtφt specifikovat Φφslo portu serveru p°φmo pomocφ vlastnosti Port nebo nep°φmo pojmenovßnφm po╛adovanΘ slu╛by pomocφ vlastnosti Service. Pokud specifikujeme obojφ, pak je pou╛ito jmΘno slu╛by.
Formovßnφ p°ipojenφ
Pokud ji╛ mßme nastaveny vlastnosti komponenty klientskΘho soketu na popis serveru ke kterΘmu se chceme p°ipojit, pak se m∙╛eme za b∞hu p°ipojit volßnφm metody Open. Pokud chceme aby na╣e aplikace se p°ipojovala automaticky p°i spu╣t∞nφ, pak nastavφme vlastnost Active p°i nßvrhu pomocφ Inspektora objekt∙ na true.
Zφskßvßnφ informacφ o p°ipojenφ
Po zkompletovßnφ p°ipojenφ na soket serveru, m∙╛eme pou╛φt objekt klientskΘho soketu Windows p°i°azen² k na╣φ komponent∞ klientskΘho soketu k zφskßnφ informacφ o p°ipojenφ. Pomocφ vlastnosti Socket zφskßme p°φstup k objektu klientskΘho soketu Windows. Tento objekt soketu Windows mß vlastnosti, kterΘ umo╛≥ujφ urΦit adresu a Φφslo portu pou╛itΘ klientsk²m a serverov²m soketem na koncφch p°ipojenφ. Vlastnost SocketHandle m∙╛eme pou╛φt k zφskßnφ madla soketu p°ipojenφ pro pou╛itφ ve volßnφch API soketu Windows. Vlastnost Handle m∙╛eme pou╛φt k p°φstupu k oknu zφskßvajφcφmu zprßvy od soketu p°ipojenφ. Vlastnost AsyncStyles urΦuje jak² typ zprßv toto madlo okna p°ijφmß.
Uzav°enφ p°ipojenφ
Po dokonΦenφ komunikace se serverovou aplikacφ pomocφ soketovΘho propojenφ, m∙╛eme zru╣it p°ipojenφ volßnφm metody Close. P°ipojenφ m∙╛e b²t takΘ ukonΦeno serverem. V tomto p°φpad∞ zφskßme oznßmenφ v udßlosti OnDisconnect.

Pou╛φvßnφ serverov²ch soket∙

P°idßnφm komponenty soketu serveru (TServerSocket) na nß╣ formulß° nebo datov² modul zapojφme na╣i aplikaci do serveru TCP/IP. Soket serveru umo╛≥uje specifikovat slu╛bu, kterou poskytujeme nebo port, kter² chceme pou╛φt k poslouchßnφ klientsk²ch po╛adavk∙. Soket serveru m∙╛eme pou╛φt k naslouchßnφ a akceptovßnφ po╛adavk∙ klient∙ na p°ipojenφ.
Ka╛dß komponenta soketu serveru pou╛φvß jeden objekt soketu serveru Windows (TServerWinSocket) k reprezentaci serverovΘho koncovΘho bodu v naslouchacφm p°ipojenφ. TakΘ pou╛φvß objekt soketu serverovΘho klienta Windows (TServerClientWinSocket) pro serverov² konec ka╛dΘho aktivnφho p°ipojenφ na klientsk² soket, kter² server akceptuje.
ServerovΘ sokety pou╛ijeme ke:
Specifikovßnφ po╛adovanΘho portu
D°φve ne╛ nß╣ serverov² soket m∙╛e naslouchat klientsk²m po╛adavk∙m, musφme specifikovat port na kterΘm nß╣ server bude naslouchat. Tento port m∙╛eme specifikovat pomocφ vlastnosti Port. Pokud na╣e serverovß aplikace poskytuje standardnφ slu╛bu, kterß je p°i°azena konvencφ ke specifickΘmu Φφslu portu, pak m∙╛eme port specifikovat nep°φmo pomocφ vlastnosti Service. P°i nastavovßnφ Φφsla portu je vhodnΘ pou╛φvat vlastnost Service. Pokud specifikujeme vlastnost Port i Service, pak soket serveru pou╛ije jmΘno slu╛by.
Naslouchßnφ klientsk²m po╛adavk∙m
Kdy╛ ji╛ mßme nastaveno Φφslo portu, pak m∙╛eme zaΦφt naslouchat p°ipojenφm, volßnφm metody Open. Pokud chceme, aby na╣e aplikace automaticky zaΦala naslouchat p°i spu╣t∞nφ, pak nastavφme vlastnost Active na true p°i nßvrhu pomocφ Inspektora objekt∙.
P°ipojovßnφ na klienty
Naslouchßnφ komponentou soketu serveru automaticky akceptuje po╛adavek klienta na p°ipojenφ, kdy╛ je p°ijat. V²skyt tΘto udßlosti je oznßmen udßlostφ OnClientConnect.
Zφskßvßnφ informacφ o p°ipojenφch
Kdy╛ ji╛ mßme otev°eno naslouchacφ p°ipojenφ na╣im serverov²m soketem, pak m∙╛eme pou╛φt objekt serverovΘho soketu Windows p°i°azen² k na╣φ komponent∞ serverovΘho soketu k zφskßnφ informacφ o p°ipojenφ. Pou╛ijeme vlastnost Socket k zφskßnφ p°φstupu k objektu serverovΘho soketu Windows. Tento objekt soketu Windows mß vlastnosti, kterΘ umo╛≥ujφ nalΘzt v╣echny aktivnφ p°ipojenφ klientsk²ch soket∙, kterΘ byly akceptovßny komponentou serverovΘho soketu. Vlastnost SocketHandle pou╛ijeme k zφskßnφ madla soketu p°ipojenφ pro pou╛itφ ve volßnφ API soketu Windows. Vlastnost Handle pou╛ijeme pro p°φstup k oknu, kterΘ p°ijφmß zprßvy od soketu p°ipojenφ.
Ka╛dΘ aktivnφ propojenφ s klientskou aplikacφ je zaobaleno objektem soketu serverovΘho klienta Windows (TServerClientWinSocket). M∙╛eme k n∞mu p°istupovat prost°ednictvφm vlastnosti Connections objektu soketu Windows. Tyto objekty soket∙ serverovΘho klienta Windows majφ vlastnosti, kterΘ umo╛≥ujφ urΦit adresu a Φφslo portu pou╛itou sokety serveru a klienta tvo°φcφch koncovΘ body propojenφ. Vlastnost SocketHandle pou╛ijeme k zφskßnφ madla soketu p°ipojenφ pro pou╛itφ ve volßnφ API soketu Windows. Vlastnost Handle pou╛ijeme pro p°φstup k oknu, kterΘ p°ijφmß zprßvy od soketu p°ipojenφ. Vlastnost AsyncStyles urΦuje jakΘ typy zprßv okno m∙╛e p°ijφmat.
Uzavφrßnφ serverov²ch p°ipojenφ
Kdy╛ chceme ukonΦit naslouchacφ p°ipojenφ, pak volßme metodu Close. Tφm ukonΦφme v╣echna otev°enß propojenφ klientsk²ch aplikacφ, zru╣φme nevy°φzenΘ p°ipojenφ, kterΘ nejsou akceptovßny a ukonΦφme naslouchacφ p°ipojenφ a tak ji╛ na╣e komponenta serverovΘho soketu nem∙╛e akceptovat ╛ßdnß novß p°ipojenφ.
Kdy╛ klienti ukonΦφ jednotlivß p°ipojenφ, pak nß╣ serverov² soket je informovßn udßlostφ OnClientDisconnect.

Reagovßnφ na udßlosti soketu

Kdy╛ zapisujeme aplikaci pou╛φvajφcφ sokety, pak v∞t╣inu prßce obvykle umis╗ujeme do obsluh udßlostφ komponent soket∙. Udßlosti OnRead a OnWrite v neblokujφcφch klientsk²ch soketech nastanou, kdy╛ prob∞hlo Φtenφ nebo zßpis pomocφ propojenφ soket∙. Podobn∞ serverovΘ sokety (blokujφcφ nebo neblokujφcφ) zφskßvajφ udßlost OnClientRead a OnClientWrite.
KlientskΘ sokety zφskßvajφ udßlost OnDisconnect kdy╛ server ukonΦφ p°ipojenφ a serverovΘ sokety zφskßvajφ udßlost OnClientDisconnect, kdy╛ klient ukonΦφ p°ipojenφ.
Dßle klientskΘ i serverovΘ sokety generujφ udßlost chyby, kdy╛ p°ijmou chybovou zprßvu od p°ipojenφ. Komponenty soket∙ takΘ p°ijφmajφ n∞kolik udßlostφ v p°φpad∞ otev°enφ a kompletovßnφ p°ipojenφ. Pokud na╣e aplikace chce ovliv≥ovat zp∙sob zpracovßnφ otevφranφ soket∙ nebo zahajovßnφ Φtenφ nebo zßpisu, pak m∙╛eme po╛adovat zapsat obsluhy udßlostφ reagujφcφ na tyto klientskΘ nebo serverovΘ udßlosti.

Udßlosti chyb

KlientskΘ sokety generujφ udßlost OnError, kdy╛ p°ijmou chybovou zprßvu od p°ipojenφ. ServerovΘ sokety generujφ OnClientError. M∙╛eme zapsat obsluhy t∞chto udßlostφ k reagovßnφ na tyto chybovΘ zprßvy. Obsluze je p°edßna informace o tom: V obsluze m∙╛eme chybu zpracovat a zm∞nit chybov² k≤d na 0 pro zabrßn∞nφ soketu v generovßnφ v²jimky.

Udßlosti klienta

Kdy╛ klientsk² soket otevφrß p°ipojenφ, pak nastanou nßsledujφcφ udßlosti:
  1. Udßlost OnLookup nastane p°ed pokusem lokalizovat serverov² soket. Od tohoto okam╛iku nem∙╛eme m∞nit vlastnosti Host, Address, Port nebo Service pro zm∞nu lokalizovanΘho serverovΘho soketu. M∙╛eme pou╛φt vlastnost Socket pro p°φstup k objektu klientskΘho soketu Windows a vlastnost SocketHandle k provedenφ volßnφ API Windows, kterΘ ovlivnφ vlastnosti soketu. Nap°. pokud chceme, pak m∙╛eme nastavit Φφslo portu klientskΘ aplikace (musφme to ud∞lat nynφ).
  2. Soket Windows je nastaven a inicializovßn pro oznamovßnφ udßlostφ.
  3. Udßlost OnConnecting nastane po lokalizaci serverovΘho soketu. Objekt soketu Windows je dostupn² pomocφ vlastnosti Socket a m∙╛e poskytnout informace o serverovΘm soketu, kter² je na druhΘm konci propojenφ. Toto je prvnφ mo╛nost zφskßnφ aktußlnφho portu a IP adresy pou╛itΘ pro propojenφ, kterΘ se mohou li╣it od portu a IP adresy naslouchacφho soketu, kter² akceptuje p°ipojenφ.
  4. Po╛adavek na p°ipojenφ je akceptovßn serverem a kompletovßn klientsk²m soketem.
  5. Po z°φzenφ p°ipojenφ vznikß udßlost OnConnect. Pokud nß╣ soket mß bezprost°edn∞ zaΦφt Φφst nebo zapisovat data pomocφ propojenφ, pak to provßdφme v obsluze udßlosti OnConnect.

Udßlosti serveru

Komponenty serverovΘho soketu majφ dva typy p°ipojenφ: naslouchacφ p°ipojenφ a p°ipojenφ ke klientskΘ aplikaci. ServerovΘ sokety p°ijφmajφ udßlosti v pr∙b∞hu formovßnφ obou t∞chto p°ipojenφ.
T∞sn∞ p°ed zformovßnφm naslouchacφho p°ipojenφ vznikß udßlost OnListen. V tomto okam╛iku m∙╛eme zφskat objekt serverovΘho soketu Windows prost°ednictvφm vlastnosti Socket. M∙╛eme pou╛φt vlastnost SocketHandle k provedenφ zm∞n na soketu d°φve ne╛ je otev°en pro naslouchßnφ. Nap°. m∙╛eme chtφt omezit IP adresy serveru pou╛itΘ pro naslouchßnφ a provedeme to v obsluze udßlosti OnListen.
Kdy╛ serverov² soket akceptuje po╛adavek klientskΘho p°ipojenφ, pak vzniknou nßsledujφcφ udßlosti:
  1. Serverov² soket generuje udßlost OnGetSocket, p°edßnφm madla soketu Windows pro soket, kter² tvo°φ koncov² bod serverovΘho p°ipojenφ. Pokud chceme poskytnout svΘho vlastnφho p°izp∙sobenΘho potomka TServerClientWinSocket, pak jej m∙╛eme vytvo°it v obsluze udßlosti OnGetSocket a tak bude pou╛it mφsto TServerClientWinSocket.
  2. Nastßvß udßlost OnAccept, p°edßvajφcφ nov² objekt TServerClientWinSocket obsluze udßlosti. To je prvnφ okam╛ik, kdy m∙╛eme pou╛φt vlastnost TServerClienWinSocket k zφskßvßnφ informacφ o koncovΘm bodu serveru p°ipojenφ na klienta.
  3. Pokud p°i vzniku udßlosti OnGetThread ServerType je stThreadBlocking, pak chceme poskytnout svΘho vlastnφho p°izp∙sobenΘho potomka TServerClientThread, tak jej m∙╛eme vytvo°it v obsluze udßlosti OnGetThread a bude pou╛φvßn namφsto TServerClientThread.
  4. Pokud ServerType je stThreadBlocking, pak nastane udßlost OnThreadStart, kdy╛ vlßkno zahßjφ provßd∞nφ. Jestli╛e chceme provΘst n∞jakou inicializaci vlßkna nebo provΘst n∞jakΘ volßnφ API soketu Windows p°ed zahßjenφm Φtenφ nebo zßpisu vlßkna v propojenφm, pak pou╛ijeme obsluhu udßlosti OnThreadStart.
  5. Klient kompletuje p°ipojenφ a vznikß udßlost OnClientConnect. S neblokujφcφm serverem m∙╛eme v tento okam╛ik zahßjit Φtenφ nebo zßpis v soketovΘm p°ipojenφ.

╚tenφ a zßpis v soketovΘm propojenφ

D∙vod formovßnφ soketovΘho propojenφ na jin² poΦφtaΦ je to, ╛e m∙╛eme Φφst nebo zapisovat informace v tomto propojenφ. JakΘ informace Φteme nebo zapisujeme nebo kdy╛ jsou Φteny nebo zapisovßny, zßvisφ na slu╛bßch p°i°azen²ch k soketovΘmu propojenφ.
╚tenφ a zßpis prost°ednictvφm soket∙ m∙╛e probφhat asynchronn∞, a tak neblokujeme provßd∞nφ jinΘho k≤du v na╣φ sφ╗ovΘ aplikaci. Toto propojenφ se naz²vß neblokujφcφ propojenφ. M∙╛eme takΘ formovat blokujφcφ propojenφ, kde na╣e aplikace Φekß na dokonΦenφ Φtenφ nebo zßpisu p°ed provedenφm nßsledujφcφho °ßdku k≤du.

Neblokujφcφ propojenφ

Neblokujφcφ propojenφ Φte a zapisuje asynchronn∞, a tak p°enß╣enß data neblokujφ provßd∞nφ jinΘho k≤du na╣φ sφ╗ovΘ aplikace. K vytvo°enφ neblokujφcφho propojenφ: Kdy╛ propojenφ je neblokujφcφ, pak Φtecφ a zßpisovΘ udßlosti informujφ nß╣ soket, kdy╛ soket na druhΘm konci propojenφ Φte nebo zapφ╣e informaci.
╚tecφ a zßpisovΘ udßlosti
Neblokujφcφ sokety generujφ Φtecφ a zßpisovΘ udßlosti, kterΘ informujφ nß╣ soket, kdy╛ je zapot°ebφ Φφst nebo zapisovat v propojenφ. V klientsk²ch soketech, m∙╛eme reagovat na tyto oznßmenφ v obsluhßch udßlostφ OnRead nebo OnWrite. V serverov²ch soketech, m∙╛eme reagovat na tyto udßlosti v obsluhßch udßlostφ OnClientRead nebo OnClienWrite.
Objekt soketu Windows p°i°azen² k soketovΘmu propojenφ je poskytnut jako parametr obsluhßm Φtecφch nebo zßpisov²ch udßlostφ. Tento objekt soketu Windows poskytuje °adu metod umo╛≥ujφcφch Φtenφ nebo zßpis v propojenφ. Ke Φtenφ ze soketovΘho propojenφ, pou╛φvßme metody ReceiveBuf nebo ReceiveText. P°ed pou╛itφm metody ReceiveBuf, pou╛ijeme metodu TReceiveLength k zφskßnφ poΦtu slabik, kterΘ soket na druhΘm konci propojenφ odeslal.
K zßpisu na soketovΘ propojenφ, pou╛φvßme metody SendBuf, SendStream nebo SendText. Pokud po zßpisu informacφ na soket ji╛ dßle soketovΘ propojenφ nepot°ebujeme, pak m∙╛eme pou╛φt metodu SendStreamThenDrop. Tato metoda uzavφrß soketovΘ p°ipojenφ po zßpisu v╣ech informacφ, kterΘ mohou b²t p°eΦteny z proudu. Pokud pou╛ijeme metodu SendStream nebo SendStreamThenDrop, pak objekt proudu nenφ uvoln∞n. Soket uvolnφ proud automaticky, kdy╛ propojenφ je uzav°eno.
Poznßmka: SendStreamThenDrop uzavφrß serverovΘ p°ipojenφ na jistΘho klienta a ne naslouchacφ p°ipojenφ.

Blokujφcφ propojenφ

Kdy╛ propojenφ je blokujφcφ, pak nß╣ soket musφ inicializovat Φtenφ nebo zßpis v propojenφ namφsto pasivnφho Φekßnφ na oznßmenφ od soketovΘho propojenφ. Blokujφcφ sokety pou╛ijeme kdy╛ nß╣ konec propojenφ mß na starosti provßd∞nφ Φtenφ a zßpisu.
Pro klientskΘ sokety, nastavφme vlastnost ClientType na ctBlocking k formovßnφ blokujφcφho propojenφ. V zßvislosti na tom co na╣e aplikace provßdφ, m∙╛eme chtφt vytvo°it novΘ b∞╛φcφ vlßkno pro Φtenφ nebo zßpis, aby na╣e aplikace mohla pokraΦovat v provßd∞nφ k≤du v jinΘm vlßknu, zatφmco Φekßme na dokonΦenφ Φtenφ nebo zßpisu.
Pro serverovΘ sokety, nastavφme vlastnost ServerType na stThreadBlocking pro formovßnφ blokujφcφho propojenφ. Proto╛e blokujφcφ propojenφ pozdr╛uje provßd∞nφ v╣eho ostatnφho k≤du b∞hem Φekßnφ soketu na Φtenφ nebo zßpis, komponenty serverov²ch soket∙ v╛dy plodφ novΘ vlßkno pro ka╛dΘ klientskΘ propojenφ, kdy╛ ServerType je stThreadBlocking.
V∞t╣ina aplikacφ, kterΘ pou╛φvajφ blokujφcφ p°ipojenφ jsou zapsßny na pou╛itφ vlßken.
Pokud nepou╛φvßme vlßkna, pak m∙╛eme Φφst nebo zapisovat pomocφ TWinSocketStream.
Pou╛φvßnφ vlßken s blokujφcφmi p°ipojenφmi
KlientskΘ sokety automaticky neplodφ novΘ vlßkno, kdy╛ Φteme nebo zapisujeme pomocφ blokujφcφho p°ipojenφ. Pokud na╣e klientskß aplikace nic ned∞lß dokud informace nenφ p°eΦtena nebo zapsßna, pak je to vyhovujφcφ. Jestli╛e na╣e aplikace obsahuje u╛ivatelskΘ rozhranφ, kterΘ musφ stßle reagovat na u╛ivatele, pak pro Φtenφ a zßpis musφme po╛adovat samostatnΘ vlßkno.
Kdy╛ serverov² soket formuje blokujφcφ p°ipojenφ, pak v╛dy plodφ samostatnΘ vlßkno pro ka╛dΘ klientskΘ p°ipojenφ a tak klient nemusφ Φekat a╛ jin² klient dokonΦφ Φtenφ nebo zßpis ve svΘm p°ipojenφ. Implicitn∞ serverov² soket pou╛φvß objekt TServerClientThread k implementaci b∞╛φcφho vlßkna pro ka╛dΘ p°ipojenφ.
Objekt TServerClientThread simuluje udßlosti OnClientRead a OnClientWrite, kterΘ vynikajφ p°i neblokujφcφm p°ipojenφ. NicmΘn∞, tyto udßlosti vznikajφ i na naslouchacφm soketu, kter² nenφ vlßknov∞ lokßlnφ. Pokud klientskΘ po╛adavky jsou ΦastΘ, pak m∙╛eme chtφt vytvo°it svΘho vlastnφho potomka TServerClientThread k poskytnutφ vlßknov∞ bezpeΦnΘho Φtenφ a zßpisu.
Kdy╛ zapisujeme klientskß vlßkna nebo zapisujeme serverovß vlßkna, pak musφme pou╛φt TWinSocketStream k provßd∞nφ aktußlnφho Φtenφ a zßpisu.
Pou╛φvßnφ TWinSocketStream
Kdy╛ implementujeme vlßkno pro blokujφcφ p°ipojenφ, pak musφme urΦit, zda soket na druhΘm konci propojenφ je urΦen pro Φtenφ nebo pro zßpis. Blokujφcφ p°ipojenφ neoznamujφ soketu Φas Φtenφ nebo zßpisu. Abychom je vid∞li, kdy╛ p°ipojenφ je reßlnΘ, pou╛ijeme objekt TWinSocketStream. TWinSocketStream poskytuje metody pomßhajφcφ koordinovat Φasy Φtenφ a zßpisu. Volßnφm metody WaitForData Φekßme, dokud soket na druhΘm konci p°ipojenφ neprovede zßpis.
Kdy╛ Φtenφ nebo zßpis pou╛φvß TWinSocketStream, pak Φas proudu je p°ekroΦen, pokud Φtenφ nebo zßpis nenφ dokonΦeno ve specifikovanΘm ΦasovΘm intervalu. V²sledkem tohoto p°ekroΦenφ Φasu je ukonΦenφ Φtenφ nebo zßpisu a zru╣enφ p°ipojenφ.
Poznßmka: TWinSocketStream nem∙╛eme pou╛φt pro neblokujφcφ p°ipojenφ.
Zßpis klientsk²ch vlßken
K zßpisu vlßkna pro klientskΘ p°ipojenφ, definujeme nov² objekt vlßkna pomocφ dialogovΘho okna New Thread Object. Metoda Execute na╣eho novΘho objektu vlßkna zpracovßvß detaily Φtenφ a zßpisu vlßknovΘho p°ipojenφ. Je vytvo°en objekt TWinSocketStream a je pou╛φvßn ke Φtenφ nebo zßpisu. Nap°.
void __fastcall TMyClientThread::Execute()
{
  // vytvo°enφ TWinSocketStream pro Φtenφ a zßpis
  TWinSocketStream *pStream=new TWinSocketStream(ClientSocket1->Socket, 60000);
  try
  {
    //zφskßnφ a zpracovßvßnφ p°φkazu dokud p°ipojenφ nebo vlßkno nenφ ukonΦeno
    while (!Terminated && ClientSocket1->Active)
    {
      try
      {
        char buffer[10];
        GetNextRequest(buffer); // GetNextRequest musφ b²t vlßknov∞ bezpeΦnß metoda
        // zßpis po╛adavku na server
        pStream->Write(buffer, strlen(buffer) + 1);
        // pokraΦovßnφ v komunikaci (Φtenφ reakce ze serveru)
        ...
      }
      catch (Exception &E)
      {
        if (!E.ClassNameIs("EAbort"))
          Synchronize(HandleThreadException()); // musφme zapsat HandleThreadException
      }
    }
  }
  __finally
  {
    delete pStream;
  }
}
K pou╛itφ na╣eho vlßkna, vlßkno vytvo°φme v obsluze udßlosti OnConnect.
Zßpis serverov²ch vlßken
Vlßkna pro serverovß p°ipojenφ jsou potomci TServerClientThread. Nem∙╛eme tedy pou╛φt dialogovΘ okno New Thread Object. Musφme je deklarovat ruΦn∞ takto:
class PACKAGE TMyServerThread : public ScktComp::TServerClientThread
{
  public
    void __fastcall ClientExecute(void);
}
K implementaci tohoto vlßkna, p°episujeme metodu ClientExecute (mφsto metody Execute).
Implementovßnφ metody ClientExecute se podobß zßpisu metody Execute vlßkna pro klientskΘ p°ipojenφ. Mφsto pou╛itφ komponenty klientskΘho soketu kterou umφstφme do na╣φ aplikace z Palety komponent, serverov∞ klientskΘ vlßkno musφ pou╛φt objekt TServerClientWinSocket, kter² je vytvo°en kdy╛ naslouchacφ soket serveru akceptuje klientskΘ p°ipojenφ. Je dostupnΘ jako ve°ejnß vlastnost ClientSocket. Dßle m∙╛eme pou╛φt chrßn∞nou metodu HandleException namφsto zßpisu svΘ vlastnφ vlßknov∞ bezpeΦnΘ obsluhy v²jimky. Nap°.
void __fastcall TMyServerThread::ClientExecute()
{
  while (!Terminated && ClientSocket->Connected) // zji╣t∞nφ ╛e p°ipojenφ je aktivnφ
  {
    try
    {
      TWinSocketStream *pStream = new TWinSocketStream(ClientSocket, 60000);
      try
      {
        char buffer[10];
        memset(buffer, 0, sizeof(buffer));
        if (pStream->WaitForData(60000)) // Dßme klientu 60 sekund k zahßjenφ zßpisu
        {
          if (pStream->Read(buffer, sizeof(buffer) == 0)
            ClientSocket->Close(); // nenφ-li p°eΦteno v 60 sekundßch, pak uzav°eme p°ipojenφ
          // zpracovßnφ po╛adavku
          ...
        }
        else
          ClientSocket->Close();
      }
      __finally
      {
        delete pStream;
      }
    }
    catch (...)
    {
     HandleException();
    }
  }
}
Varovßnφ: Serverov² soket odklßdß pou╛φvanΘ vlßkno. Musφme si b²t jisti, ╛e metoda ClientExecute provede nezbytnΘ inicializace jako v²sledek zm∞ny z poslednφho provedenΘho vlßkna.
K pou╛itφ na╣eho vlßkna, vytvo°φme obsluhu udßlosti OnGetThread. Kdy╛ zapisujeme vlßkno, pak nastavφme parametr CreateSuspended na false.

  1. Podφvejme se na aplikaci Chat, kterß umo╛≥uje "rozmlouvat" dv∞ma u╛ivatel∙m na r∙zn²ch poΦφtaΦφch. Jednß se op∞t o ji╛ hotovou aplikaci. M∙╛ete si ji stßhnout. ProhlΘdn∞te si, jak vyu╛φvß sokety a vyzkou╣ejte ji.
10. Prßce se sokety