UNIVERSITÄT LEIPZIG Mainframe Internet Integration Prof. Dr. Martin Bogdan Prof. Dr.-Ing. Wilhelm G. Spruth SS2013 Java Remote Method Invocation RMI Beispiel el0100 © copyright Abt. Technische Informatik, Institut für Informatik, Univ. Leipzig wgs 04-11 RMI Tutorial Was hier folgt, ist ein RMI Tutorial. Es ist nicht abgabepflichtig und wird hier aufgeführt, um ggf. Ihr Verständnis zu verbessern. Falls Sie Lust haben, können Sie es auf Ihrem PC implementieren. Ein Zugriff auf z/OS ist nicht vorgesehen. Ein einfaches RMI Beispiel Wir implementieren als ein einfaches Beispiel die folgende Anwendung. Client Server Registry Ein Klient sendet eine Anfrage an ein Server Objekt. Dieses erzeugt eine Antwort und sendet sie an den Klienten zurück. Damit der Klient das Server Objekt finden kann konsultiert er einen Namensdienst, die Java Registry. Normalerweise laufen Klient und Server auf getrennten Rechnern, die über ein TCP/IP Netz miteinander verbinden sind. In unserem einfachen Fall laufen sie als getrennte Prozesse in getrennten virtuellen Adressenräumen auf dem gleichen Rechner. Das Klientenprogramm QuadratClient sendet eine Ziffer an den Server. Dieser multipliziert die Ziffer mit sich selbst und sendet das Ergebnis zurück an den Klienten. Dieser gibt das Ergebnis auf dem Bildschirm aus. Die Objekt-Registrierung rmiregistry Wie bekommt ein Client Zugriff auf ein Quadrat-Objekt? Wir wissen: Stub für Client, Skeleton für Server. • Der Server muss das Skeleton unter einem (möglichst eindeutigen) Namen bei einer rmiregistry anmelden. • Diese rmiregistry muss auf demselben Rechner laufen, auf dem das Remote-Objekt (Skeleton) ausgeführt wird! • Der Client muss 1. den URL der rmiregistry kennen, von der er einen Stub des Objekts bekommen kann (z.B. : rmi://jedi.informatik.uni-leipzig.de:4711, und 2. den Namen des Objekts kennen, unter dem der Stub bei der Registry bekannt ist. Vorgehensweise und Programmstruktur (1) In unserem Beispiel fordert ein Klient das Quadrat einer (Biginteger-) Zahl von dem Server an. Dies geschieht, indem er eine Methode Quadrat(BigInteger ) des Servers mit Benutzung der entfernten Referenz eines Serverobjekts aufruft. Auf der Seite des Servers werden wir dann die folgenden Schritte durchführen: 1. Eine Quadrat Schnittstelle (Quadrat.java) definieren; 2. Eine QuadratImpl Klasse (QuadratImpl.java) schreiben, welche die Quadrat Schnittstelle implementiert; 3. Eine Server Klasse (QuadratServer.java) mit einer main() Funktion für die Erzeugung des entfernten Objektes und seine Anbindung an das RMI-Registry schreiben. Vorgehensweise und Programmstruktur (2) Interface Client Implementierung Server Unsere Anwendung heist Quadrat und besteht aus 4 Java Programmen: Quadrat.java QuadratImpl.java QuadratServer.java QuadratClient.java Sie bewirkt folgendes: Es ist möglich, die Server Funktionen einer einzigen Klasse mit einer main() Funktion zu vereinigen. Die Aufteilung hat den Vorteil, dass mehrere entfernte Objekte mit einer main() Funktion erzeugt werden können. Die File Quadrat.java definiert das entfernte Objekt. Die entfernte Interface implementiert QuadratImpl.java . Die Klasse QuadratImpl.java soll als Vorlage für die Erzeugung von Skeleton und Stub dienen und benutzt dafür die in Quadrat.java definierte Schnittstelle. Die Klasse QuadratServer.java soll eine main()-Funktion beinhalten mit folgenden Aufgaben: • Einen RMISecurityManager erzeugen und installieren und • das entfernte Objekt bei der rmiregistry registrieren Definition einer entfernten Schnittstelle Damit der Client eine entfernte Methode nutzen kann, muss er ein Stellvertreterobjekt befragen. Dieses packt die Daten ein und übermittelt sie. Diese Hilfsfunktionen sollen automatisch generiert werden. Damit der Generator korrekten Quellcode für die Übertragung erstellen kann, ist eine Beschreibung nötig. Die Definition muss die Signatur eindeutig spezifizieren, und damit weiß der Client, wie die Funktion aussieht, die er aufrufen kann, und der Server kann die Methode dann beschreiben. Normalerweise gibt es für die Spezifikation der entfernten Funktionen spezielle Beschreibungssprachen (wie IDL bei CORBA), doch bei RMI reicht es, ein Java-Interface mit den Methoden zu definieren. Interface Quadrat.java Entfernte Methoden werden durch das Interface java.rmi.Remote definiert: // Interface import java.rmi.*; import java.math.BigInteger; public interface Quadrat extends Remote { public BigInteger quadrat(BigInteger n) throws RemoteException; } Die entfernten RMI-Klassen sind durch Schnittstellen spezifiziert, welche java.rmi.Remote erweitern sollen. In einer entfernten Schnittstelle werden die Methoden deklariert, die man von anderen Java Virtuellen Maschinen aufrufen kann. Für unser Beispiel definieren wir eine einzige Schnittstelle Quadrat, für die wir die Methode Quadrat(BigInteger ) deklarieren. Die Schnittstelle muss public sein, damit Klienten Zugang auf sie haben können. Eine RemoteException kann z.B. bei Kommunikations-fehlern auftreten: • wenn das entfernte Objekt nicht mehr verfügbar ist, • wenn das Netz gestört ist. Eigenschaften der Schnittstellen-Beschreibung Wir können mehrere wichtige Eigenschaften der Schnittstelle feststellen: Die entfernte Schnittstelle ist öffentlich. Wenn sie nur paket-sichtbar oder eingeschränkter ist, kann der Client die entfernte Methode nicht finden, wenn er danach verlangt. Die eigene Schnittstelle erweitert die Schnittstelle Remote. Nur die Klassen, die Remote implementieren, können entfernte Methoden anbieten. Remote ist allerdings leer und damit eine Markierungsschnittstelle. Die angebotenen Methoden können nicht beabsichtigte Fehler auslösen, zum Beispiel, wenn das Transportsystem zusammenbricht. Für diesen Fall muss jede Methode RemoteException in einer throws-Anweisung aufführen. Eine entfernte Funktion darf Parameter besitzen. Sind die Argumente primitive Werte, so werden diese einfach übertragen. Handelt es sich um Objekte, so müssen diese serialisierbar sein. http://www.galileocomputing.de/openbook/javainsel4/javainsel_18_004.htm#Rxx365java18004040007541F015100 QuadratImpl.java // QuadratImpl.java, Quadrat implementation import import import import java.rmi.*; java.rmi.server.UnicastRemoteObject; java.math.BigInteger; java.math.BigInteger.*; public class QuadratImpl extends UnicastRemoteObject implements Quadrat { private int sum; public QuadratImpl() throws RemoteException { super(); } public BigInteger quadrat(BigInteger n) throws RemoteException { BigInteger res = new BigInteger("0"); res = n.multiply(n); return res; } } Die QuadratImpl Klasse (QuadratImpl.java) implementiert die Quadrat Schnittstelle (Quadrat.java). Nur die in der entfernten Schnittstelle (Quadrat.java) deklarierten Methoden (hier quadrat(BigInteger n) )können von Klienten aufgerufen werden. Server-Programme implementieren das Interface Remote und erweitern PortableRemoteObject, welches die wichtigsten Methoden für die Verwendung von RMI bereitstellt. Statt UnicastRemoteObject wird häufig PortableRemoteObject verwendet. PortableRemoteObject ermöglicht zusätzlich den Einsatz von RMI/IIOP. Die Methoden des Servers werden letztendlich vom Client über die Stellvertreter genutzt. Der Server muss unterschiedliche Vorgaben erfüllen: Er muss eine spezielle Klasse erweitern, einen Konstruktor anbieten und die entfernte Schnittstelle implementieren. Dann kann ein Server-Objekt angemeldet werden. Das Server-Objekt implementiert daher die Geschäftslogik Da die Klasse eine Implementierung der Schnittstelle ist, geben wir ihr die Endung Impl. (Das ist eine bekannten Namensgebung aber keine Pflicht.) Die Implementierung erweitert die Klasse UnicastRemoteObject . Sie liegt im Paket java.rmi.server. Diese Klasse UnicastRemoteObject bietet Hilfe bei der Übertragung der Daten mittels Standard-TCP-Sockets an. Der Server kann so auf eingehende Anfragen reagieren und diese bearbeiten. Weiterhin zeigt UnicastRemoteObject an, dass ein Exemplar unserer Klasse existieren soll. Für den Konstruktor eines entfernten Objekts gelten zwei Eigenschaften: Wir müssen einen Standard-Konstruktor anbieten, und dieser muss ebenso wie die Methoden RemoteException anzeigen. public QuadratImpl() throws RemoteException { } Der Standard-Konstruktor ist notwendig, da eine Unterklasse genau diesen aufrufen möchte. Unser Konstruktor muss nichts machen. Er ruft aber automatisch den Konstruktor der Oberklasse auf, also den von UnicastRemoteObject. UnicastRemoteObject hilft bei der Übertragung; wenn ein entferntes Objekt konstruiert wird, dann bindet er diesen Dienst an einen anonymen Port und horcht auf einkommende Aufrufe. Wollten wir einen speziellen Port nutzen, müssten wir im Konstruktor unserer Unterklasse einen parametrisierten Konstruktor von UnicastRemoteObject aufrufen, der einen Port annimmt. Im nächsten Schritt müssen die Methoden der Schnittstelle implementiert werden. Es steht frei, andere Methoden anzugeben, die nicht in der Schnittstelle vorgegeben sind, doch diese sind dann natürlich nicht nach außen sichtbar. public BigInteger quadrat(BigInteger n) throws RemoteException { BigInteger res = new BigInteger("0"); res = n.multiply(n); return res; } Die Argumente und Rückgabewerte können von jedem beliebigen Datentyp sein. RPC RPC RPC Service Service Service RPC Server andere Prozesse Betriebssystem Kernel Die RPC Services (RPC Dienstprogramme) können entweder in getrennten virtuellen Adressenräumen laufen, oder alternativ als Threads innerhalb eines virtuellen Adressenraums implementiert werden. Ein RPC Service wird auch als Implementation bezeichnet. Häufig Hunderte oder Tausende unterschiedlicher RPC Services auf dem gleichen Rechner. Der RPC Server stellt Verwaltungsdienste für seine RPC Services zur Verfügung, z.B. das Binding. Auf einem Rechner können mehrere RPC Server laufen, die z.B. unterschiedliche Arten von RPC Services gruppieren. QuadratServer.java // QuadratServer.java import java.net.*; import java.rmi.*; import java.rmi.server.*; public class QuadratServer { public static void main(String args[]) { // Create and install the security manager System.setSecurityManager (new RMISecurityManager()); try { // Create QuadratImpl QuadratImpl QDR = new QuadratImpl(); Naming.rebind("Quadrat", QDR); System.out.println ("Quadrat Server ready."); } catch (RemoteException e) { System.out.println ("Exception: " + e.getMessage()); } catch (MalformedURLException e) { System.out.println(e); } } } Das Server-Programm enthält eine main()-Funktion, die die ganze Anwendung startet. Ein QuadratImpl Objekt, das auf Abfragen von Klienten wartet, wird dabei erzeugt und mit einem Namen bei der Registry angemeldet. Die java.rmi Package enthält eine Default Security Manager Implementierung die mit System.setSecurityManager(new RMISecurityManager()); installiert wird. In unserer Serverklasse haben wir 1. einen security manager erstellt und installiert: System.setSecurityManager(new RMISecurityManager()); Ohne dies ist kein entfernter Methodenaufruf möglich. 2. eine Instanz eines entfernten Quadrat Objekts erstellt: QuadratImpl QDR = new QuadratImpl(); Dieses Objekt wird automatisch exportiert, da die Implementierungsklasse die PortableRemoteObject Klasse erweitert. 3. das entfernte Objekt beim Namensdienst mit der Methode rebind() eingetragen (mit dem RMI-registry registriert): Naming.rebind("Quadrat", QDR); Die Funktion rebind() bindet den Namen "Quadrat" an die Referenz des entfernten Objekts (der Name Quadrat wird mit dem Objekt QDR gebunden). Klienten können danach einen lookup nach dem Objekt mit diesem Namen ausführen und dadurch eine entfernte Referenz auf das Objekt erhalten. QuadratClient.java // QuadratClient.java import java.rmi.*; import java.math.BigInteger; try { remote = Naming.lookup("rmi://" +args[0]+ "/Quadrat"); Quadrat myQDR = (Quadrat) remote; System.out.println("OK"); public class QuadratClient { public static void main(String args[]) { BigInteger res; Remote remote = null; System.setSecurityManager (new RMISecurityManager()); BigInteger n = new BigInteger(args[1]); res =myQDR.quadrat(n); System.out.println(res); } catch(Exception e) { System.err.println("System Exception" + e); } //System.out.println (System.getSecurityManager()); System.exit(0); } } Das Klientenprogramm QuadratClient.java nimmt 2 Argumente auf der Kommandozeile auf: · · Den Namen der Servermaschine, wo das entfernte Objekt registriet ist, und die Zahl, von der das Quadrat berechnet soll Unser Klientenprogramm ist zunächst ein normales Java-Programm. Um die entfernte Methode Quadrat(Biginteger ) des Servers aufrufen zu können, werden wir in der entsprechenden main() Funktion die folgende Schritte durchführen: • einen Securitymanager erstellen und installieren; • einen lookup()-Aufruf ausführen, um eine Referenz auf das entfernte Objekt zu bekommen: Naming.lookup("rmi://Serverhost/Quadrat"); Um nun die entfernte Methode zu nutzen, muss ein entferntes Objekt gesucht und angesprochen werden. Dazu fragen wir den Namensdienst. Der Name für das Objekt setzt sich zusammen aus der URL und dem Namen des Dienstes. Bei Port-Angaben dürfen wir nicht vergessen, diesen wieder hinter einem Doppelpunkt anzugeben. Der Typ des entfernten Objektes, den die Naming.lookup() Methode zurückgibt, muss der Typ der entfernten Schnittstelle Quadrat sein. In unserer Klientenanwendung werden die Adresse der Servermaschine in args[0], und die Zahl, von der das Quadrat berechnet soll, in args[1] eingegeben. Vorgehensweise 1. Interface definieren, mit der das Remote Object aufgerufen wird. > extends interface java.rmi.Remote . 2. Implementierung der Server Anwendung schreiben. Muss die Remote Interface implementieren. . > extends java.rmi.server.UnicastRemoteObject 3. Klassen kompilieren. 4. Mit dem Java RMI Compiler Client Stubs und Server Skeletons erstellen. 5. Klient implementieren und übersetzen. 6. Start Registry, Server starten, Klienten starten. > rmic xyzServerImpl Rmic Compiler Optionen Bevor rmic zum Zuge kommt, müssen die entfernten Klassen und Schnittstellen übersetzt sein. Danach geben wir auf der Kommandozeile ein: rmic QuadratImpl Die erzeugten Klassen werden standardmäßig im aktuellen Verzeichnis platziert. (Mit der Option -D lässt sich der Zielort ändern.) Das RMI-Protokoll gibt es mittlerweile in unterschiedlichen Version. Mit dem Schalter –vXXX beziehungsweise -iiop lässt sich dies genauer angeben. Weitere rmic Compiler Optionen: • -v1.1 erzeugt Stub und Skeleton für das Protokoll unter JDK 1.1. • -v1.2 erzeugt den Stub für das Java-SDK 1.2. Skeletons werden dort benötigt, da das System automatisch die Methoden des Servers findet und aufruft. • -vcompat Das Standardprotokoll unter dem JDK 1.2. Es ist kompatibel mit dem neuen 1.2 Stub-Protokoll und dem älteren von 1.1. • -iiop erstellt die für CORBA passenden Bausteine (neben iiop hat Corba weitere Protokolle standardisiert, die aber nur wenig Bedeutung haben). Mit der Option -idl kann zusätzlich für CORBA eine Spezifikationsdatei erstellt werden. Möchten wir zu den generierten Klassen den Quellcode sehen, so müssen wir -keep angeben. An den generierten Klassen lässt sich schön ablesen, wie die Kommunikation über die Leitung wirklich abgewickelt wird. Der RMI Namensdienst (Registry) Durch den Namensdienst kann ein Server entfernte Objekte mit einem Namen anmelden, und Clients können die entfernten Objekte unter einem Namen finden. Für den Namensdienst können unterschiedliche Programme eingesetzt werden, beim Java-SDK ist ein einfaches Programm dabei. Der beigefügte Namensdienst ist ein vereinfachter Object Request Broker (ORB), wie er bei CORBA bekannt ist. Unter Windows starten wir den Dienst in einer DOS-Box als getrennten Prozess (sozusagen im Hintergrund) mit folgender Zeile: start rmiregistry Die Registry können wir uns somit als einen einfachen Assoziativspeicher vorstellen, der Namen und Stub-Objekte verbindet. Der Zustand des Stubs wird bei der Registry hinterlegt. Registry Port Der Namensdienst läuft standardmäßig auf dem Port 1099. Für Dienste hinter einer Firewall ist es bedeutend, dass dieser Port auch anders lauten kann. Eine andere Port-Nummer lässt sich einfach als Argument angeben: start rmiregistry 2001 Der angegebene Port dient nur der Vermittlung vom Client zum Namensdienst. Die Kommunikation von Client und Server läuft über einen anderen Port. Implementierung Schritt 1: Vorgefertigte Java Programme übersetzen Wir kompilieren die vorgefertigten Client- und Server-Quellcode-Programme. Hierzu die DOS Kommando-Zeile Eingabe Aufforderung aufrufen. In das Verzeichnis C:\example\jrmp wechseln. Das Verzeichnis enthält 4 *.java Files. C:\example\jrmp>dir Verzeichnis von C:\example\jrmp 20.01.2005 20.01.2005 08.11.2003 17.11.2002 14.12.2002 17.11.2002 15.11.2002 11:01 11:01 21:29 11:35 18:08 11:35 10:23 <DIR> <DIR> 76 189 852 521 619 . .. .java.policy Quadrat.java QuadratClient.java QuadratImpl.java QuadratServer.java C:\example\jrmp>javac *.java C:\example\jrmp>dir Verzeichnis von C:\example\jrmp 20.01.2005 20.01.2005 08.11.2003 17.11.2002 14.12.2002 17.11.2002 15.11.2002 20.01.2005 20.01.2005 20.01.2005 20.01.2005 11:01 11:01 21:29 11:35 18:08 11:35 10:23 16:38 16:38 16:38 16:38 <DIR> <DIR> 76 189 852 521 619 238 1.229 526 1.061 . .. .java.policy Quadrat.java QuadratClient.java QuadratImpl.java QuadratServer.java Quadrat.class QuadratClient.class QuadratImpl.class QuadratServer.class Diese 4 *.java Files übersetzen mit javac *.java Wenn die Eingabeaufforderung ohne Ausgabe einer weiteren Meldung erscheint, war die Übersetzung erfolgreich. In dem Verzeichnis C:\example\jrmp befinden sich jetzt zusätzlich zu den 4 *.java Files weitere 4 entsprechende *.class Files. C:\example\jrmp>javac *.java C:\example\jrmp>dir Verzeichnis von C:\example\jrmp 20.01.2005 20.01.2005 08.11.2003 17.11.2002 14.12.2002 17.11.2002 15.11.2002 20.01.2005 20.01.2005 20.01.2005 20.01.2005 11:01 11:01 21:29 11:35 18:08 11:35 10:23 16:38 16:38 16:38 16:38 <DIR> <DIR> 76 189 852 521 619 238 1.229 526 1.061 . .. .java.policy Quadrat.java QuadratClient.java QuadratImpl.java QuadratServer.java Quadrat.class QuadratClient.class QuadratImpl.class QuadratServer.class Stub- und Skeleton-Compiler rmic Für eine Klasse, die das Interface Remote implementiert, erzeugt der RMI-Compiler rmic die benötigten Stubs und Skeletons. Der Aufruf rmic QuadratImpl erzeugt: QuadratImpl_Stub.class und QuadratImpl_Skel.class Implementierung Schritt 2: Stubs und Skeletons mit dem rmic Compiler erzeugen Jetzt für die vorgefertigte Server Anwendung QuadratImpl mit Hilfe des rmic Compilers Stubs und Skeletons erstellen mit dem Kommando rmic QuadratImpl Jetzt befinden sich in dem Verzeichnis C:\example\jrmp zusätzlich die beiden class Files QuadratImpl_Skel.class und QuadratImpl_Stub.class. C:\example\jrmp>rmic QuadratImpl C:\example\jrmp>dir Verzeichnis von C:\example\jrmp 20.01.2005 20.01.2005 08.11.2003 17.11.2002 14.12.2002 17.11.2002 15.11.2002 20.01.2005 20.01.2005 20.01.2005 20.01.2005 20.01.2005 20.01.2005 11:01 11:01 21:29 11:35 18:08 11:35 10:23 16:38 16:38 16:38 16:38 18:46 18:46 C:\example\jrmp> <DIR> <DIR> 76 189 852 521 619 238 1.229 526 1.061 3.301 1.770 . .. .java.policy Quadrat.java QuadratClient.java QuadratImpl.java QuadratServer.java Quadrat.class QuadratClient.class QuadratImpl.class QuadratServer.class QuadratImpl_Stub.class QuadratImpl_Skel.class Die Policy – Sicherheitsaspekte Wenn eine benötigte class-Datei von einem öffentlichen Web-Server oder aus einem entfernten Verzeichnis(-Dienst) geholt werden soll, müssen gewisse Regelungen bzgl. Sicherheit getroffen werden. Für diesen Zweck wird in den RMI-Programmen der RMISecurityManager gesetzt. Dieser verhält sich gemäß den Regeln, die in der Datei $HOME/.java.policy angegeben werden. Am einfachsten, aber auch am unsichersten, wäre folgendes .java.policy: grant { permission java.security.AllPermission; }; RMI (bzw. das zugrunde liegende Protokoll JRMP) verwendet Sockets, deshalb müssen mindestens SocketPermissions gesetzt werden, etwa: grant { permission java.net.SocketPermission "localhost", "accept,connect,listen"; permission java.net.SocketPermission "*. lrz-muenchen.de", "accept,connect,listen"; }; Die Pakete java.rmi und java.rmi.server selbst definieren keine Permissions. Daher müssen in .java.policy keine weiteren RMI-spezifische Permissions gesetzt werden. Einen Überblick über mögliche Permissions gibt http://java.sun.com/j2se/1.4.2/docs/guide/security/permissions.html. Weitere Beispiele für Policy-Files z.B. in http://java.sun.com/j2se/1.4.2/docs/guide/security/PolicyFiles.html#Examples. Zur Erstellung der Datei .java.policy kann auch das GUI-basierte policytool aus dem JDK verwendet werden. Dokumentation in http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/policytool.html. Damit sind wir in der Lage, unsere Anwendung in Betrieb zu nehmen. Neben unserem Klienten brauchen wir 3 weitere Prozesse: • den eigentlichen Server Prozess • den Namensdienst Java Registry • den RMISecurityManager, das Policy Tool In unserem Beispiel laufen diese drei Prozesse auf dem gleichen Rechner wie der Klient. In diesen Prozessen laufen eigene JVMs (Java virtuelle Maschinen). In der Praxis würden diese Prozesse normalerweise auf getrennten Servern laufen, obwohl es durchaus sinnvoll sein kann, mehrere JVMs auf dem gleichen Server zu unterhalten, Hiervon macht z.B. die z/OS Version von WebSphere Gebrauch. Die drei Prozesse Server, Registry und Policy müssen auf ihren jeweiligen Rechnern gestartet werden, ehe die Klientenanwendung durchgeführt werden kann. In unserem Beispiel starten wir die drei Prozesse auf dem gleichen Rechner auf dem unser Klient läuft. Dies geschieht mit Hilfe des Start Kommandos: start policytool start rmiregistry start java QuadratServer Nachdem die Prozesse gestartet sind können wir unseren Klienten aktivieren mit dem Kommando java QuadratClient ( parameter ) Es geht los. Inbetriebnahme Schritt 1: auf der Command Line eingeben start policytool Es werden zwei neue Fenster geöffnet: C:\j2sdk1.4.0_02\bin\policytool.exe und Richtlinietool. Diese repräsentieren den Security Prozess. Inbetriebnahme Schritt 2: Ausserdem erscheint in der untersten Leiste rechts ein Eintrag „Richtlinientool“. Auf diesen Eintrag mit der linken Maustaste einmal klicken. Jetzt im Verzeichnis C:\example\jrmp auf der Command Line eingeben start rmiregistry Das C:\j2sdk1.4.0_02\bin\rmiregistry.exe Fenster erscheint. Der Registry Prozess wurde gestartet Inbetriebnahme Schritt 3: Jetzt im Verzeichnis C:\example\jrmp auf der Command Line eingeben start java QuadratServer Damit wird der Server gestartet. Das H:\j2sdk1.4.0_02\bin\java.exe Fenster erscheint. Inbetriebnahme Schritt 4: Jetzt im Verzeichnis C:\example\jrmp auf der Command Line eingeben java QuadratClient localhost 5 Bezeichnung des Server Objektes Eine attraktiven Präsentationslogik gefällig ? Internet Adresse des Server Objektes Die Ziffer 5 ist das Argument, was von der Server Anwendung quadriert werden soll. Die folgende Message erscheint C:\example\jrmp>java QuadratClient localhost 5 OK 25 Und dies ist das Ergebnis der Anfrage des Clienten : java QuadratClient localhost 5 Das Ergebnis ist 25 Ergebnis der Anfrage des Clienten : Glückwunsch. Sie haben erfolgreich ein RMI Programm erstellt. Dies sind die 4 übrigen geöffneten Fenster