Delphi Socket Komponensei
A
következőkben szeretném bevezetni az olvasót, a Delphiben
megismert Client (kliens) és Server (szerver) socket komponensek világába, amiről már rengeteg cikket
olvashattunk, de talán ezzel a cikkel a kezdők jobban elindulhatnak és
elsajátíthatják a TCP/IP programozás alapjait. A jobb megértéshez egy
példaprogramot is mellékelek. Véleményem szerint ez a cikk hasznos lehet
azoknak, akik még csak most ismerkednek a Delphivel
és a kliens-szerver alkalmazásokkal.
Alapjában véve mi is az a TCP/IP kliens?
Egy
felhasználói program (alkalmazás), amely meghatározott portra
csatlakozik a TCP/IP szerveren keresztül és adatokat cserél akár stream vagy szöveges formátumban.
Mi kell ahhoz hogy létrehozz egy TCP/IP alkalmazást Delphiben?
A
legegyszerűbb módja, hogy felveszel egy TClientSocket
komponenst - amit az Internet palettán találhatsz meg - és ide állítsd be a
következő tulajdonságokat:
Address
(cím): Ide annak a TCP/IP szervernek az IP címe kerül, amihez ez a kliens
csatlakozik.
Host (hoszt):
A cím (address) helyett ide egy
alias nevet írhatsz az IP címnek a Host
tulajdonságokban. Nyilvánvaló, hogy be kell állítani vagy a címet vagy a host tulajdonságokat. De mi van akkor, ha mindkettő megvan?
A host a cím felett áll a beállítás szerint, így ezt
nézi elsődlegesen a fordítónk.
A Host tulajdonság beállítása jobb, mint a címé, mert még ha meg is változtatod a TCP/IP szervert egy másik
gépre vagy más IP címre váltasz, amíg az alias név megmarad, nem kell
megváltoztatni azt a TCP/IP kliensen. (még akkor is ha
kissé feleslegesnek tűnik, hogy válaszoljon a host az
annak megfelelő IP címre, megéri ha van...)
Port .: Ez
egy érvényes integer port szám ahol a TCP/IP szerver
figyel és válaszol. Ez mindig egy állandó szám a szerverhez kötve. Ehhez a port
számhoz a kliens kapcsolódik, valamint adatot küld/kap.
Service
(szolgáltatás).: Mint a host
és az address tulajdonságok egyféleképp egymáshoz
kötöttek, így Port és Service is. Általánosságban a Service az, amit a TCP/IP
szerver nyújt a klienseinek (mint például http, ftp ).
Ezek az általános szolgáltatások egy külön porthoz
vannak hozzárendelve a szerveren. (pl.: http a port
40-hez). Felmerülhet a kérdés, hogyan működik ez valójában. A szerveren van egy
services fájl, amelyben a szolgáltatásokat a
viszonylagos portjaikkal mappeli
(kapcsolja) össze, így saját szolgáltatás leírásaid lehetnek, amelyek egy
meghatározott portra mappelnek
(mutatnak) a szerveren. Így a kliens a szolgáltatáshoz tud kapcsolódni,
felhasználva a szolgáltatás tulajdonságot és elvégzi a feladatát.
ClientType
(kliens típus): Ez a tulajdonság határozza meg, hogy a kölcsönhatás a szerver
és a kliens közt szinkron vagy aszinkron módon jön-e létre.
ctNonBlocking (nem
blokkoló, alapértelmezett) Ebben az esetben a szerver és kliens között a
kölcsönhatás aszinkron, azaz a kliens tud adatot küldeni a szervernek és
megvárja az OnRead adat végrehajtódását, amikor az
adat a szervertől visszaérkezik.
vtBlocking –
(blokkoló) Ez a szerver-kliens közötti kölcsönhatás szinkron módú
végrehajtódásához kell.
Mikor tegyük a Client Code-ot (kliens kód) szálbiztossá?
(thread-safe mód)
Ha több, mint
egy kérés küldődik egyidejűleg a kliens alkalmazástól
a szerver felé, akkor ajánlott a "client code" thread-safe módba
ültetése. Más esetben a kérés-válasz összeomolhat. (request-response)
Mikor rakjuk a Server Code-ot
thread-safe módba? (szálbiztos
mód)
Ha egyidejűleg
több mint egy kérés érkezik, akár kliens alkalmazástól,
akár különböző kliens alkalmazásoktól, akkor ajánlatos, hogy a "server code" thread-safe módban legyen. Ez általánosan használható
minden TCP/IP szerver számára, a programnyelvtől független módon.
Melyik a legjobb hely a TClientSocket
komponens beépítésére az alkalmazásunkban?
A komponenst
teheted DataModule formátumba. Ha csak egy páratlan
formátumod van a kliens alkalmazásban, ami a
szerverrel kommunikál, akkor nincs probléma a TClientSocket
komponenssel ebben a formátumban. De ha sok formátumod van a kliens
alkalmazásban, akkor jobb ötlet a komponenst DataModul
formátumba rakni és ezt alkalmazni, ahol csak kell.
Hogy kapcsolódsz a szerverhez?
Állítsd be az
összes tulajdonságot, amit fentebb említettem, majd vagy az aktív tulajdonságot
állítsd igazra (active tulajdonság true) vagy használd az Open
módot. Amint létrejön a kapcsolat, az adatküldést vagy a SendText
vagy a SendStream rutinokkal teheted meg. Ne felejtsd
el, hogy az OnClientSocketRead rutint használhatod a
szervertől visszaérkező adat olvasására.
Mi az a TCP/IP szerver?
Olyan alkalmazás,
amely egy meghatározott porton figyel és válaszol a
klienseknek. Ez akármilyen általános szerver lehet
mint például http, ftp vagy
akármilyen másik szerver az egyéni alkalmazásokhoz.
Mi kell ahhoz, hogy Delphivel
csinálj egyet?
Ugyanúgy, mint
a kliens esetén, egy TServerSocket komponens kell a
következő beállításokkal:
Port.: Bármely integer adatot írhatsz ide.
Ehhez a porthoz a kliens kapcsolódhat és
kommunikálhat.
Service: Mint
már említettem, a port-hoz kapcsolódóan lehet
szolgáltatás neved.
Ha szervert
mondunk, akkor több mint egy klienst kellene egyszerre kiszolgálni tudnia, mert
csak ekkor van értelme. Most a legfontosabb következő kérdés, hogyan
kommunikálnak a kliensek a szerverrel: több kliens egyszerre vagy egy kliens
egy időben. Ez egy következő beállítás alkalmazásához vezet, mely meghatározza,
hogy a kliensek a szerverrel szinkron vagy aszinkron módon kommunikálnak.
Hogyan kezeljük több kliens kérését egyszerre?
A megoldás az,
hogy hozzunk létre egy új szálat minden kliens kérésnek.
Ez elérhető a ServerType tulajdonság stThreadBlocking értékre állításával. Nem minden új szál létrehozás (spawning) és
megszüntetés kell, hogy rendelkezzen megkerülő lehetőséggel (overhead). De ha az alkalmazásunk elrendezése kívánja,
akkor kell a megkerülő lehetőség. Felmerülhet a kérdés, csökkenthető-e az overhead szálak létrehozásával és eltüntetésével? A válasz
egyértelműen igen. És hogyan? Rejtsd el a szálakat!
A ThreadCacheSize tulajdonság szolgálja ezt a célt. Az
alapérték 10, de ez az érték a kliens alkalmazásod igényeitől függ. Ezzel a
beállítással vigyázni kell! Ha maxra állítod, memória
bajokkal kell szembenézned. Ha túl alacsonyra, a kliensnek várakozási ideje
lesz minden kérelemnél. A megoldás a legjobb érték beállítása a kliens
statisztikája alapján.
Ha a kliens kérelmek egy időben, egyszerre jönnek, akkor a ServerType
tulajdonságot stNonBlockingra állíthatod.
Hogy olvasunk vissza adatot a klienstől?
Mint ClientSocket, ott van az OnClientRead
rutin, amely visszaolvassa az adatot a klienstől.
Nagyjából
ennyi lett volna a kliens és szerver socket
bemutatása, ha problémád vagy kérdésed van, e-mail útján megteheted.
*** Forrás mellékelve – delphi.zip ***
Gebei János – ircadmin@aom.hu