Da ich mich gerade im Rahmen meines Studiums mit RMI beschäftigen muss, dabei aber immer wieder auf veraltete Tutorials gestossen bin, ab Version 5 verhält sich RMI etwas anders als noch unter den Vorgängerversionen, werde ich an dieser Stelle eine kurzes und knappes Tutorial zum Erstellen einer sehr simplen RMI-Anwendung bereitstellen.
RMI steht für Remote Method Invocation und bedeutet in etwa so viel wie “Entfernter Methodenaufruf”. Sinn und Zweck der Übung ist es, Daten zwischen Server und Client auszutauschen, indem die Methoden des jeweils anderen Systems aufgerufen werden. Geregelt wird all dies über ein Interface, in dem die zum entfernten Aufruf bestimmten Methoden definiert werden. Mit diesem Interface möchte ich meine Kurzeinführung nun auch beginnen:
package de.ulfklose.rmi.tryouts;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface ServerInterface extends Remote
{
int getValue() throws RemoteException;
}
In diesem Interface, ServerInterface.java, haben wir nun eine Methode namens getValue() definiert, die eine RemoteException wirft, sollte beim Transfer der Daten irgendetwas schief laufen. Die Imports sind verpflichtend, da unser Interface Remote aus dem Package java.rmi extended und die eben erwähnte RemoteException werfen soll.
Jetzt machen wir uns an die Implementierung des Servers. Hier erst mal der Code:
package de.ulfklose.rmi.tryouts;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class Server extends UnicastRemoteObject implements ServerInterface
{
private int value;
Server() throws RemoteException
{
super();
this.value = 3; // Der Variablen int den Integer-Wert 3 zu weisen
}
public int getValue() throws RemoteException
{
System.out.println("getValue() wurde aufgerufen"); // Server gibt bei jedem Client-Aufruf von getValue() diesen String aus
return this.value; // Server übermittelt aktuellen Wert von "value" an Client
}
public static void main(String[] args)
{
try {
LocateRegistry.createRegistry(Registry.REGISTRY_PORT); // Server an der Registry anmelden
System.out.println("Server registered, up and running."); // kurze Statusmeldung an der Konsole des Servers ausgeben
}
catch (RemoteException ex) {
System.out.println(ex.getMessage());
}
try {
Naming.rebind("Server", new Server()); // Server-Objekt mit dem Namen "Server" erstellen, dies ist nun der Server-Name
}
catch (MalformedURLException ex) {
System.out.println(ex.getMessage());
}
catch (RemoteException ex) {
System.out.println(ex.getMessage());
}
}
}
Das war’s schon. Wichtig sind auch hier wieder die Imports, ohne die wir keinen Zugriff auf die RMI-Klassen von Java hätten. Theoretisch sollte es auch genügen, java.rmi.* zu importieren. Hier gehen wir etwas expliziter vor. In Zeile 10 implementieren wir das Interface ServerInterface.java, außerdem extenden wir UnicastRemoteObject, welches die Kommunikation via Remote überhaupt erst ermöglicht. Über die Kommentare im Code sollte der Großteil eigentlich klar sein. Näher erläutern möchte ich an dieser Stelle noch die Zeilen 28 und 35:
In Zeile 28 melden wir unsere Serverapplikation an der so genannten Registry an. Die dafür notwendigen Methoden stehen im Package java.rmi.registry. zur Verfügung und werden für den hinter RMI arbeitenden Namensdienst benötigt. Der übergebene Port ist frei wählbar, muss aber im öffentlichen Bereich liegen, also darf Port 1000 und größer verwendet werden. Wird kein Port explizit gesetzt, läuft der Server auf Port 1099 und nimmt dort Anfragen von Clients entgegen. In Zeile 35 verwenden wir diesen Namensdienst und geben unserem Server einen konkreten Namen, über den der Client eine Verbindung zu diesem aufbauen kann. In unserem Fall wird die Instanz der Klasse Server an den Namen “Server” gebunden. Logischerweise darf auf einer Maschine jeweils nur eine Instanz mit dem gleichen Namen existieren. Im nachfolgenden sehen wir, wie der Client nun auf den Server zugreifen und die zur Verfügung gestellten Methoden aufrufen kann (Remote Method Invocation).
package de.ulfklose.rmi.tryouts;
import java.rmi.Naming;
public class Client {
public static void main(String[] args) {
try {
ServerInterface server = (ServerInterface)Naming.lookup("//ip.v4.adresse.hierher/Server"); // Verbindung zu Server aufbauen, Name wird in Server.java definiert
System.out.println("Connection to server established.");
System.out.println("Folgender Wert wurde vom Server erhalten: " + server.getValue()); // Methodenaufruf von Server
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
}
}
Die Klasse Client.java importiert den RMI-Namensdienst in Zeile 3. In der Main-Methode wird dann eine Instanz des Interfaces erstellt. Über den Namensdienst bauen wir eine Verbindung zu unserem Server auf. Dieser kann entweder in einer weiteren virtuellen Maschine auf der gleichen physikalischen Maschine laufen oder auf einem anderen Rechner im erreichbaren Netzwerk. Soll die Kommunikation über die Grenzen des eigenen Netzwerks erfolgen, müssen eventuelle Firewalls entsprechend konfiguriert werden. In Zeile 11 schlussendlich rufen wir die Methode getValue() vom Server auf, die wir im Interface definiert haben. Beim Aufruf der Methode wird auf dem Client der aktuelle Wert (in unserem Falle 3) der Variablen “value” mit dem vorangestellten String (Zeile 12) ausgegeben, der Server wiederum gibt auf seiner Konsole den Text “getValue() wurde aufgerufen” aus.
Ja, richtig, das war es schon. Jetzt suche ich gerade nach spannenden Sachen, die ich mit diesen Erkenntnissen noch anstellen kann 😀 Sollte jemand eine tolle Idee haben, immer her damit. Und ich hoffe, dem einen oder anderen eine leicht verständliche Anleitung über die Grundlagen von RMI unter Java gegeben zu haben.
Ich habe den kompletten Quellcode aller drei Klassen auch bei attachr.com geparkt, vielleicht sind die dort besser lesbar, falls jemand hier Probleme haben sollte:
3 Antworten zu “Einfache RMI-Anwendung mit Java”
Danke, du hast mir damit das Leben gerettet. Im ganzen Netz gibt es keinen der das Thema so gut erklaert hat. Ne passende Main methode (anwendung) waere noch hilfreich gewesen aber sonst. Nicht schlecht. Nochmals Danke. Amsel
Gern geschehen. Ich nehme an, dass du die main mittlerweile selbst geschrieben hast, oder? 😉
hm…
Ich schließe mich dem Danke an.
Ich sitze hier zwar immer noch, wie der Ochs vorm Berge, aber der Nebel des Unverständnisses hat sich ein kleines bisschen gelichtet. 🙂
Es besteht Hoffnung — vielleicht *denk*
LG Michaela