IX. A hálózat használa

Bevezetés

Ebben a leckében a NetREXX azon területével foglalkozunk, amelyek segítségével lehetôség nyílik hálózaton keresztül kommunikáló kliens/szerver alkalmazások készítésére. A NetREXX esetében a kommunikáció nyelve a TCP/IP protokoll, amely egyben az internet nyelve is. Gondolom senkit sem lep meg, hogy ebben a leckében is rendszeresen a Java nyelv által nyújtott lehetôségekre fogunk hivatkozni. Szó lesz például az RMI (Remote Method Invocation) eljárásról, amely segítségével a kiszolgálón található Java osztályok metódusait lehet távolról végrehajtani, valamint érintjük a WWW használatához nélkülözhetetlen URL osztályt is.

A socketek

A TCP/IP protokollt használó alkalmazások kommunikálásának leggyakrabban használt módja a socket (magyarul talán aljzatnak vagy foglalatnak fordítható) technológián alapszik. Az alapötlet az, hogy mind a kliens, mind pedig a szerver oldali programnak létre kell hozni egy socket objektumot, amelyre rácsatlakozva kommunikálhatnak egymással. Az alap socket eljárásokat a Socket és a ServerSocket Java osztályok tartalmazzák, amelyek java.net csomagban találhatóak. A socket objektumot egyértelmûen definiálja a socketet azonosító IP szám vagy kiszolgálónév és a portszám, amely WWW kiszolgáló esetében általában 80:

az_elso_aljzatom = Socket('www.alaplap.hu', 80)

Mindegyik sockethez tartozik egy bemeneti és egy kimeneti stream is, amelyeken az adatforgalmat lehet lebonyolítani a fájlok kezelésekor már megismert getInputStream és getOutputStream metódusokkal. A továbbiakban tekintsünk meg egy programot, amely egy socket segítségével küld el egy parancsot a webkiszolgálóhoz, majd pedig megjeleníti a szerver válaszát:

/* lecke09a.nrx */

parse arg server port str

if server = "" | port = "" then do
	say "Használat: java lecke09a <szerver> <portszám> <parancs>"
 	exit 1
end

parse str get rest
if get <> "" then do
	if get <> "GET" then do
		say "A parancs formátuma: GET /http-oldal"
 		exit 8
 	end
 	str = "GET" rest
end
 
do 
	say "Kapcsolódás a kiszolgálóhoz: "server" (port: "port")"
 	mysocket = Socket(server, port)
 	say "Parancs: "str
 	say

	-- a kimeneti és bemeneti streamek definiálása
 	out = PrintWriter(OutputStreamWriter(mysocket.getOutputStream()))
 	in = BufferedReader(InputStreamReader(mysocket.getInputStream()))
 	out.printLn(str) -- a parancs elküldése
	out.flush() -- szükség van rá a multiplatformos kompatibilitás miatt

 	say "Válasz:"
 	line = String(in.readLine())
 	loop while line \= null
 		say " "line	-- a válasz kiíratása
 		line = in.readLine()
 	end

catch e = IOException -- hibahelyzetek lekezelése
 say "IOException ("e") történt:\n" e.getMessage()

end

A parancssorban megadott paraméterek ellenôrzése után definiáljuk a socketet és az arra csatlakozó kimeneti és bemeneti streameket. A parancsot a kimeneti stream printLn metódusával küldjük el, a szerver válaszát pedig a bemeneti streambôl olvassuk ki a readLine metódus segítségével. Hiba esetén tájékoztatjuk a felhasználót a hiba okáról.

A kipróbáláshoz elôször fordítsuk le a NetREXX programot, majd futtassuk az eredményül kapott Java programot a java lecke09a www.alaplap.hu 80 GET / parancs kiadásával. Amennyiben gépünkrôl elérhetô a www.alaplap.hu kiszolgáló, akkor válaszul megkapjuk az Új Alaplap internetes fôoldalát. Mivel a kliens program nem tudja értelmezni a HTML nyelvet, ezért egyszerûen kilistázza a képernyôre a szerver által visszaküldött sorokat. Ha a kimenetet fájlba irányítjuk, akkor a fájlt egy böngészôprogramba betöltve teljes pompájában nézhetjük meg az oldalt. Amennyiben a GET /valahol/valami.htm parancsot adjuk ki, akkor azzal egyéb oldalakat is lekérhetünk. Elvileg másfajta kiszolgálókra is küldhetünk parancsot, ha megfelelô portszámot adunk meg. Egy ftp szerverrel például a java lecke09a os2.rulez.org 21 GET / paranccsal lehet kapcsolatba lépni, ám az (a példában HTTP parancsról lévén szó) hibaüzenetet fog visszaküldeni.

Most pedig nézzük meg, hogy hogyan lehet szerver oldali socketekkel dolgozni! Ezen socketek definiálásához csak a portszámot kell megadni:

az_elso_szerveraljzatom = ServerSocket(80)

Ezek után már nem is kell mást tennünk, mint várakozni a kapcsolódó kliensekre a szerver socket objektum accept metódusának meghívásával:

kliens_aljzat = az_elso_szerveraljzatom.accept()

Az accept metódus blokkolja a program futását és csak akkor tér vissza, amikor a kliens kapcsolatot létesít a szerverrel. A metódus visszatérési értéke egy kliens socket objektum, amely segítségével a szerver és a kliens kommunikálhatnak egymással. Következô példaprogramban éppen azt mutatjuk be, hogy hogyan lehet a szerver oldali socketek segítségével web-kiszolgálót írni NetREXX-ben.

/* lecke09b.nrx */

do
 	if arg = "" then arg = 80 	-- alapértelmezett port
 	serverS = ServerSocket(arg) -- regisztráljuk a szerver socketet
 	say "Szerver: "serverS

 	loop forever
 		serviceS = serverS.accept() -- várjuk a kliens kapcsolódását
 		say serviceS "\n kapcsolódott. Idô: "Date()
 		ptrW = PrintWriter(OutputStreamWriter(serviceS.getOutputStream()))
 		sIS = BufferedReader(InputStreamReader(serviceS.getInputStream()))

 		loop while sIS.ready() -- feldolgozzuk a HTTP parancsokat
 			line = String(sIS.readLine())
 		end

 		filename = "ntrx09.htm" -- mindig a leckét küldjük vissza
 		fileBR = BufferedReader(FileReader(filename))
 		line = String(fileBR.readLine())
 		loop while(line <> null)
 			ptrW.printLn(line)
 			line = fileBR.readLine()
 		end

 		ptrW.close() -- zárjuk a kapcsolatot
 		serviceS.close()

catch e = IOException
 		say "IOException történt: "e.getMessage()
 	end

end

A program elején definiáljuk a szerver socketet, majd egy végtelen hurokban várakozunk a kliensek hívásaira. Amikor a kapcsolódás megtörténik, akkor létrehozzuk az adatforgalomhoz szükséges streameket. Szintén egy hurokban olvassuk ki a kliens által küldött parancsot, mivel az több sorból is állhat. A példában szereplô kiszolgáló a parancstól függetlenül, mindig ezen lecke szövegét küldi vissza. A sikeres tranzakció után zárjuk a kapcsolatot és várjuk a következô hívást. A példaprogram tesztelhetô internetes kapcsolat nélkül is. Elég ugyanis, ha gépünkön beállítjuk az úgynevezett loopback interfészt. A helyes mûködést úgy ellenôrizhetjük, hogy kiadjuk a ping 127.0.0.1 parancsot. Sikeres pingetés után fordítsuk le a NetREXX programot (nrc lecke09b.nrx) és indítsuk el a szervert a java lecke09b paranccsal. Egy másik ablakban adjuk ki a java lecke09a 127.0.0.1 80 GET / utasítást. Válaszul meg kell kapnunk ennek a leckének a szövegét. A sikeres mûködéshez elengedhetetlen, hogy az említett összes fájl egy könyvtárban legyen és ugyaninnen futtassuk a programokat is. A szervert természetesen bármilyen böngészôbôl is tesztelhetjük a http://127.0.0.1 URL beírásával.

Mind a szerver, mind pedig a kliens oldali socket rendelkezik négy attribútummal, amelyek értékébôl a socket néhány alapjellemzôjére lehet következtetni:

A második példaprogramban bemutatott web kiszolgálónak van egy nagy problémája. Nem képes ugyanis egyszerre több kliens kiszolgálására. Ha azt akarjuk, hogy a szerver több klienssel is tudjon egy idôben kapcsolatot létesíteni, akkor a kliens kapcsolódása után indítanunk kell egy szálat, amely a továbbiakban elvégzi a klienssel történô kommunikációt. Íly módon a fôprogramban található "kliensfigyelô" rész aktív maradhat és fogadhatja a többi klienst is:

loop forever	-- a várakozási hurok
	serviceS = serverS.accept() -- várjuk a csatlakozást
 	st = ServerThread(serviceS) -- szálobjektum készítése
 	Thread(st).start() -- a szál indítása
end

A többszálon futó web-kiszolgálót nem mutatjuk be részletesen, ám megtalálható a példaprogramok között (lásd lecke09c.nrx). Mindenképpen érdemes tanulmányozni a mindössze 2Kb-ra rúgó programot!

Az URL osztály használata

Nem kell socket szintre lemenni, ha URL osztályt használunk egyszerû böngészôprogramunk megírására. Az URL-ek általános alakja:

<protokoll>://<kiszolgáló>[:<port>]/<fájl>[#<referencia>]

Bármelyik összetevô értékét le lehet kérdezni a megfelelô metódusokkal:

Egy másik nagyon fontos metódus a getContent metódus, amellyel az URL objektum tartalma, vagyis az URL által reprezentált állomány kérhetô le. Gyakran találkozunk még Java programokban az openConnection metódussal is, amellyel például az adat letöltése elôtt annak típusa kérdezhetô le. A továbbiakban tekintsük meg leckénk negyedik példaprogramját, amely az URL osztály segítségével tölti le a paraméterként megadott URL által reprezentált oldalt:

/* lecke09d.nrx */

parse arg prot "://" request 

if prot = "" | request = "" then do
 	say "Használat: java lecke09d <URL>"
 	exit 8
end

do
 	ourURL = URL(arg) -- URL objektum készítése
 	say "URL: "ourURL
 	content = ourURL.getContent() -- letöltés
 	say "Tartalom:\n"
 	bR = BufferedReader(InputStreamReader(InputStream content))
 	line = String(bR.readLine()) 
 	loop while(line <> null)
 		say line
 		line = bR.readLine()
 	end

 catch e = IOException
 	say "IOException történt: "e"\n"e.getMessage()
end

A program a szokásos paraméterellenôrzés után készít egy URL objektumot, majd letölti annak tartalmát a már említett getContent metódussal. Mivel a getContent egy objektum típusú objektumot ad vissza, ezért azt át kell alakítani valamilyen más típusra, amelyet aztán fel tudunk majd dolgozni. A példaprogramban az InputStream adattípust választottuk, amelyet pufferelünk, és az így kapott adatokat egy hurok segítségével soronként jelenítjük meg. Bár ez a példaprogram elsô látásra nem csinál sokkal többet, mint a socketes alapokon írt elsô példaprogram, az URL objektum használata miatt azonban ez utóbbi akár tûzfalon keresztül is képes az URL-ek letöltésére.

Örömünk azonban gyorsan véget érhet, mivel bizonyos oldalak letöltése közben nagyon könnyen az alábbi, vagy ahhoz hasonló hibaüzenetet kaphatunk:

java.lang.ClassCastException:
 at lecke09d.main(lecke09d.nrx:15)

A hibát az okozza, hogy a getContent metódus által visszaadott objektumot nem lehet InputStream típusúra alakítani. Ez például akkor fordul elô, ha mondjuk egy képet akarunk letölteni. Böngészôprogramunkat tehát fel kell készíteni a különbözô adattípusok felismerésére és azok lekezelésére. (A Java nyelv által támogatott típusok leírását a Java motor lib alkönyvtárának conttype.prp, vagy valami ehhez hasonló nevû fájljában tanulmányozhatjuk.) Képek esetében az ImageProducer, hanganyagok esetében pedig az AudioClip típusokat szokás használni. Az alábbi kódrészletben azt mutatjuk be, hogy hogyan lehet különbséget tenni a különbözô fajtájú adatok között (a komplett példaprogramot megtaláljuk a lecke09e.nrx fájlban):

ourURL = URL(arg) -- az URL objektum elkészítése
say "URL      : "ourURL
urlConn = ourURL.openConnection() -- kacsolódunk az URL objektumhoz
conttype = Rexx urlConn.getContentType() -- lekérdezzük az adat típusát
say "Adattípus: "conttype
content = urlConn.getContent() -- lekérjük az állományt
say "Osztály  :" content.getClass().getName()
select
	when content <= ImageProducer then -- kép
		say "Adatosztály: ImageProducer"
	when content <= AudioClip then do -- zene
		say "Adatosztály: AudioClip"
		(AudioClip content).play() -- le is játsszuk
	end
	when content <= InputStream then do  -- InputStream 
		say "Adatosztály: InputStream"
		say "Tartalom :\n"
		bR = BufferedReader(InputStreamReader(InputStream content))
		line = String(bR.readLine())
		loop while(line <> null)
			say line
			line = bR.readLine()
		end
	end
	otherwise
		say "Ismeretlen adatosztály!"
end

Amint látjuk, az URL objektum létrehozása után készítünk egy connection objektumot is, melynek getContentType metódusával megtudakolhatjuk a letöltendô adat típusát. Ezek után a NetREXX a Java-ban az InstanceOf operátornak megfelelô <= operátorával döntjük el, hogy melyik osztályba tartozik a visszakapott objektum. Kép esetén nem csinálunk semmit (a lekezelés túl bonyolult lenne egyszerû programocskánk számára), zene esetében viszont lejátsszuk a letöltött állományt, szöveg esetében pedig kinyomtatjuk a kapott sorokat a képernyôre.

Kivételes események

A hálózati erôforrások manipulálása közben szinte minden pillanatban történhet valamilyen váratlan esemény, amely lekezelését a klasszikus programnyelvek esetén magunknak kellett megoldani. A NetREXX esetében ezt a feladatot látja el a Java nyelv kivételes eseményeket lekezelô mechanizmusa (exception handling). A java.net csomag használata közben öt kivételes esemény következhet be. Az egyik eseménynek, a SocketExceptionnek ezen kívül létezik még három aleseménye, amelyekbôl pontosabban behatárolható a hiba oka. Az alábbi táblázatban összefoglaltuk ezeket az eseményeket, illetve azokat a hivatkozásokat, amelyek felelôsek lehetnek az adott esemény bekövetkezéséért.

Kivételes esemény:Elôidézô kódrészlet:
MalformedURLExceptionURL konstruktorok, RMIClassLoader.loadClass(), LoaderHandler.loadClass()
ProtocolExceptionHttpURLConnection.setRequestMethod()
SocketException (BindException, ConnectException, NoRouteToHostException)ServerSocket.setSoTimeout(), setSocketFactory(), Socket konstruktor, setSocketFactory(), setSoTimeout(), SocketOutputStream.write(), DatagramSocket konstruktorok, create(), getSoTimeout(), setSoTimeout(), MulticastSocket.create(), setInterface(), getInterface(), RMISocketFactor.setSocketFactory()
UnknownHostExceptionInetAddress konstruktor, getByName(), getAllByName(), getLocalHost(), Socket konstruktor, URL hiba
UnknownServiceExceptionURL konstruktorok, getInputStream(), getOutputStream()

Nagyon fontos, hogy programjainkban figyeljünk a fenti eseményekre és bekövetkezésük esetén megfelelôen kezeljük le ôket!

Távoli metódusok

Elosztott programok írására alkalmas a Remote Method Invocation (távoli metódusok meghívása) technológia, amely az RPC-nek (Remote Procedure Call, magyarul távoli eljárások meghívása) az objektum orientált megfelelôje. Az RMI lényege az, hogy a programot felépítô komponensek különbözô gépeken helyezkednek el és ezek a hálózat segítségével kommunikálnak egymással. Az RMI használatához szükséges osztályok a java.rmi és java.rmi.server csomagokban találhatók. Távoli objektumokra egy RMI URL-lel hivatkozhatunk, amelynek általános alakja a következô:

rmi://<kiszolgáló>:<port>/<objektumnév>

Az URL második és harmadik összetevôje opcionális, mivel a használni kívánt objektum ugyanazon gépen is elhelyezkedhet, ahol a kliens is fut. Ebben az esetben az rmi:///objektum névvel is lehet az objektumra hivatkozni. Elsô RMI-vel kapcsolatos példánkban egy kliensprogramot valósítunk meg, amely a felhasználó által begépelt üzeneteket juttatja el a szerveren elhelyezkedô objektumhoz, egészen addig, amíg az end szót be nem gépelik:

/* lecke09f.nrx */

import java.rmi.
import lecke09g

parse arg serverAdr . -- a kiszolgáló nevének feldolgozása
if serverAdr = "" then serverAdr = "localhost"
urlstring = "rmi://"serverAdr"/Listener"

do
 	say "Regisztrálás a Security Managernél ..."
 	System.setSecurityManager(RMISecurityManager())
 	say "Keressük a partnert a "serverAdr" kiszolgálón..."
 	Listener = lecke09g Naming.lookup(urlstring) -- a szerver objektum
	say Listener
 	loop forever
 		say "Gépeld be a küldendô szöveget (end = kilépés)"
 		smalltalk = ask
 		if smalltalk = "end" then leave
 		else Listener.listen(smalltalk) -- RMI hívás
 		say "Az üzenet sikeresen továbbítva.\n"
	end

 	catch e1 = RemoteException
 		say "Sikertelen RMI!"
 		say "RemoteException történt:\n"e1.getMessage()

 	catch e2 = java.net.MalformedURLException
 		say "Hibás URL: "urlstring
 		say "MalformedURLException történt:\n"e2.getMessage()

 	catch e3 = Exception
 		say "Exception ("e3") történt:\n"e3.getMessage()
 
end

say "Az RMI kliensprogram befejezôdött."

A programot a java.rmi. csomagok betöltésével kezdjük, s regisztrálunk egy lecke09g osztályt is, amelyben a távoli (szerver) objektum azon metódusait definiáljuk, amelyek elérhetôek a kliensek számára (interfész). Esetünkben ez egyetlen metódusra, a listenre korlátozódik:

/* lecke09g.nrx */

import java.rmi.

class lecke09g interface implements Remote
method listen(str = String) public signals RemoteException

A távolról meghívható metódusok interfészének minden esetben implementálnia kell a Remote interfészt és a metódusokat public-nak kell deklarálni, amelyek RemoteExceptiont generálhatnak. A kliensprogram ezután feldolgozza a parancssorban megadott kiszolgáló nevét. Amennyiben nem adunk meg paramétert, akkor automatikusan a localhost, vagyis a loopback (127.0.0.1) adapterhez tartozó nevet helyettesíti be a program. A kiszolgáló nevének tisztázása után összeállítjuk az RMI URL-t. A távoli objektum neve Listener, amelyet jelen esetben egyszerûen beírtunk a programba, ám igény esetén ezt is meg lehetne adatni a parancssorban. A következô elôkészítô lépés a regisztrálás a Java Security Managarénél, amelyre azért van szükség, hogy használni tudjuk a távoli osztályokat. A Security Manager ugyanis ellenkezô esetben nem engedné meg a bizonytalan eredetû osztályok betöltését. A regisztrálást követi a kiszolgálói objektum definiálása. Erre szolgál a java.rmi csomag részét képezô Naming osztály lookup metódusa, amely úgymond megkeresi a kiszolgálón a kérdéses objektumot. Sikeres végrehajtás esetén egy hurokban folytatódik a program futása, ahol bekérjük a felhasználó üzeneteit és a távoli objektum publikus, listen metódusával küldjük el azt. End begépelése esetén kilépünk a programból. A további kód a hibahelyzetek lekezelésével foglalkozik, ezekre most nem térünk ki részletesen.

A szerver oldali program hasonlóan egyszerû:

/* lecke09h.nrx */

import java.rmi.
import java.rmi.server.
import lecke09g

/* az RMI szerver osztály */
class lecke09h public extends UnicastRemoteObject implements lecke09g

method main(args=String[]) public static

do
 	hostname = "localhost"
 	if args.length = 1 then hostname = args[0]
	say "Regisztrálás a Security Managernél..."
 	System.setSecurityManager(RMISecurityManager())
 	say "Publikáljuk az objektumot: rmi://"hostname"/Listener"
 	Listener = lecke09h() -- a szerver objektum
 	Naming.rebind("rmi://"hostname"/Listener", Listener) -- bind Listener
 	say "Várom a kliens kapcsolódását..."
 
	catch e = Exception
 	say "Exception ("e") történt:\n"e.getMessage()
end

method lecke09h() signals RemoteException -- konstruktor

-- publikus interfész
method listen(str = String) public signals RemoteException
 
do
 	say "A kliens "getClientHost()" által küldött szöveg:\n"str

 	catch ServerNotActiveException
 	say "Csak a szerver használhatja a listen metódust!"
end

A program a szokásos csomag- és osztályregisztrációval indul, amelyet követ a szerver osztály definiálása. Az RMI szervert minden esetben egy, a Remote Server absztrakt osztályból leszármaztatott osztályra kell alapozni. Esetünkben az UnicastRemoteObject osztályból származtatjuk a lecke09h szerverosztályt, amely lehetôvé teszi egyszerre több kliens csatlakozását is. Az osztály fômetódusában regisztráltatjuk magunkat a Security Managernél, majd pedig létrehozzuk a szerverobjektumot, amelyet publikálunk a már korábban is használt Naming osztály rebind metódusával. Elvileg elég lenne a bind metódus is, ám ebben az esetben elôször a unbind metódussal kellene az elôzô futtatások eredményét eltûntetni. A rebind automatikusan végrehajtja az unbindot a bind elôtt, ezért inkább ezt érdemes használni. Ezek után a szerver már kész is a kliensek üzeneteinek a fogadására. A program végén találjuk még a publikus listen metódus megvalósítását, amely esetünkben nem csinál mást, mint megjeleníti a kliens által küldött üzenetet.

A fenti példaprogramok kipróbálása kicsivel több elôkészületet igényel mint amit eddig megszoktunk. Ahhoz, hogy a kliensek meg tudják találni a kiszolgálón a távoli objektumokat (lásd lookup metódus), futtatni kell az úgynevezett RMI regisztrációs szervert, amely nyilvántartja az RMI szerverek által publikált objektumokat. A szerverprogramban használt bind/rebind metódus nem csinál mást, mint beíratja a regisztrációs szerver adatbázisába az általa publikált objektumok referenciáit. Miután lefordítottuk a programokat a NetREXX fordítóval, el kell indítanunk a kiszolgálón a regisztrációs szervert. Ezt a start rmiregistry.exe parancs (egyes operációs rendszereken rmiregst.exe) kiadásával tehetjük meg. A szerver- és a kliensobjektumok transzparens kommunikációját az úgynevezett stub (csonk) és skeleton (csontváz) osztályok valósítják meg. Minden távoli objektumhoz el kell készíteni ezeket az osztályokat, amelyet az RMI fordítóprogrammal tehetünk meg: rmic lecke09h. Ezek után már nincs más hátra, mint hogy elindítsuk a szerver- (java lecke09h), majd pedig a kliensprogramot (java lecke09f <szerver>). Ha mindent jól csináltunk, akkor a kliens üzenetei sikeresen el fognak jutni a kiszolgálón futó komponenshez, amely megjeleníti azokat. A példaprogramok akkor is mûködnek, ha ugyanazon a gépen futtatjuk a kliens és a szerverkomponenst, telepítve van a TCP/IP, konfigurálva van a loopback interfész és a host táblázatban megadtuk a loopback interfész címének és a localhost névnek az összetartozását.

REXX GYÍK:

K1. Az RMI példaprogram nem mûködik gépemen, pedig mindent úgy csináltam, ahogy a leckében le van írva. Mi lehet a probléma?
V1. Az RMI regisztrációs programnak hozzá kell férni a stub és skeleton osztályokhoz. Elôször is ellenôrizzük, hogy fel van-e sorolva a CLASSPATH környezeti változóban az osztályokat tartalmazó könyvtár. Ha nem, akkor orvosoljuk a problémát. Ha a . benne van a CLASSPATH-ban, akkor azzal is eredményt érhetünk el, ha az osztályokat tartalmazó könyvtárból indítjuk a regisztrációs programot.

K2. Nincs a gépemen RMI fordítóprogram, pedig telepítettem a Java motort. Hogyan tovább?
V2. Valószínûleg nem telepítette az RMI fordítóprogramot tartalmazó Java komponenst. Az újabb kiadású IBM-es Java motoroknál például ez a komponens az RMI/IIOP ToolKit része.

K3. Mi a CORBA és az RMI kapcsolata?
V3. Mint láttuk, az RMI technológia segítségével Java/NetREXX alapú, elosztott programokat készíthetünk. Hasonló célokat szolgál a CORBA is. Az RMI által használt kommunikációs protokoll azonban nem szabványos és nem is kompatibilis a CORBA objektumok által használt IIOP protokollal, így azokkal korábban nem tudtak az RMI objektumok együttmûködni. Az újabb IBM-es Java motorokban megtalálható RMI-IIOP ToolKit segítségével készített RMI objektumok azonban már képesek az IIOP protokoll támogatására is, így a két technológia keverhetô.


Gyakorlatok:

1. Írja át az RMI példaprogramokat oly módon, hogy az egyirányú adatforgalom helyett kétirányúra legyen lehetôség!

2. Készítsen Java alapú IRC szerver és kliensprogramot!

Kádár Zsolt
2000. 06. 30.
[ Elôzô lecke | Következô lecke | Tartalom ]