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:
-
systém na kterém je spuštěn
-
typ rozhraní, kterému rozumí
-
port použitý pro připojení
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:
-
Který objekt soketu Windows přijal oznámení chyby.
-
Co soket dělal v okamžiku výskytu chyby.
-
Chybový kód poskytnutý chybovou zprávou.
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:
-
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í).
-
Soket Windows je nastaven a inicializován pro oznamování
událostí.
-
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í.
-
Požadavek na připojení je akceptován serverem a kompletován
klientským soketem.
-
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:
-
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.
-
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.
-
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.
-
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.
-
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í:
-
Na klientském soketu nastavíme vlastnost ClientType
na ctNonBlocking.
-
Na serverovém soketu nastavíme vlastnost ServerType
na stNonBlocking.
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.
-
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.