# RMI Verständnisfrage



## Sunbird (22. Okt 2009)

Hi Leute!

Ich will eine Client-Server Anwendung mit RMI schreiben.

Um etwas genauer zu werden:
Der Server Teil soll auf einem eigens dafür angeschafften Server laufen während der Client auf unterschiedlichen Rechnern laufen wird.

Der Server soll vor allen Dingen Datenbank Querys in seinen lokalen Speicher schreiben. Die Datenbak beinhaltet sehr viele Datensätze die oft durchlaufen werden müssen um nach verschiedenen Werten zu schauen. In wie weit das funktioniert und der Speicher ausgelastet wird muss man dann mal schauen. Jedenfalls ist es absolut unpraktikabel wenn der Client jedes Mal ein eigenes Query absetzt und auf dessen Ergebnis warten müsste. Ich denke beim Server an 8GB RAM und hoffe das reicht aus. Es kommen nur einmal täglich neue Daten so das man das Rowset nur einmal am Tag füllen müsste.

Server und Client laufen NICHT auf dem gleichen Rechner. Ich hoffe das lässt sich mit RMI programmieren. Sonst müsste ich das ganze als Sockets selber schreiben.

Da ich aber vorher noch mit RMI gearbeitet habe möchte ich erstmal nur ein kleines Programm haben das einen einfachen String vom Server zurückgibt um die funktionsweise zu verstehen.

*Server*

Remote Interface

```
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface TestService extends Remote{

    public String greeting() throws RemoteException;
}
```

Remote Implementation

```
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class TestServiceImpl extends UnicastRemoteObject implements TestService{

    public TestServiceImpl() throws RemoteException{
    }

    @Override
    public String greeting() throws RemoteException{
        return "Dieser String wird vom Server geliefert";
    }
}
```

Registry

```
import de.server.services.TestService;
import de.server.services.TestServiceImpl;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RemoteServer;
import java.rmi.server.UnicastRemoteObject;

public class Main {

    
    public static void main(String[] args) throws RemoteException{
        try{
            LocateRegistry.createRegistry(Registry.REGISTRY_PORT);

            TestServiceImpl greet = new TestServiceImpl();
            TestService stub = (TestService)UnicastRemoteObject.exportObject(greet, 0);
            RemoteServer.setLog(System.out);

            Registry registry = LocateRegistry.getRegistry();
            registry.rebind("TestService", stub);

            System.out.println("TestService angemeldet");
        }
        catch(Exception e){

        }
    }

}
```


Das lässt sich kompilieren und erfolgreich starten durch aufruf des .jar Files.

*Client*

Ich möchte das der String nach dem betätigen eines jButtons in die Konsole geschrieben wird.

```
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        try {
            java.rmi.registry.Registry registry = java.rmi.registry.LocateRegistry.getRegistry();
            TestService greet = (TestService) registry.lookup("TestService");
            System.out.println(greet.greeting());
        }catch(Exception e){
            
        }
    }
```
Das Problem: Natürlich kann ich das so nicht kompilieren da das TestService Interface unbekannt ist da es ja im .jar File des Servers liegt.

Mein Verständnisproblem ist nun folgendes:
Klar kann ich das .jar File des Servers in den Klassenpfad des Clients legen nur bekomme ich dann eine Antwort aus genau dem jar? Ich möchte ja das ich die Antwort von meinem entfernten Server bekomme.

Hat jemand Erfahrungen mit Client Server Anwendungen bei denen der Serverteil auch auf einem physikalisch entfernten Rechner liegt?

Bin für jede Hilfe dankbar.

Gruß
Sunbird


----------



## tfa (22. Okt 2009)

> Server und Client laufen NICHT auf dem gleichen Rechner. Ich hoffe das lässt sich mit RMI programmieren.


Na klar. Genau dafür ist es gedacht.



> Mein Verständnisproblem ist nun folgendes:
> Klar kann ich das .jar File des Servers in den Klassenpfad des Clients legen nur bekomme ich dann eine Antwort aus genau dem jar? Ich möchte ja das ich die Antwort von meinem entfernten Server bekomme.


Du solltest dir ein JAR machen, das die Klassen bzw. Interfaces enthält, die von beiden Seiten benutzt werden. Es gibt zwar auch noch die Möglichkeit, dass die Clients per Remote-Classloading die Klassen vom Server beziehen, aber normalerweise geht es mit einem gemeinsamen JAR einfacher.


----------



## Sunbird (22. Okt 2009)

Was mich nur verwirrt ist das ich dann das Server.jar einmal auf den entfernten Server lege(und starte) und dann aber auch meinen Clients(als Library) mitgebe. Das macht auf mich den eindruck als ob aus dem, dem Client mitgelieferten Server.jar heraus Methoden aufgerufen werden die dann ja nicht den Speicher des entfernten Servers nutzen sondern den Speicher des jeweiligen Clients. Und genau das will ich ja nicht haben weil ich nicht weiss wieviel RAM die Clients haben.


----------



## tfa (22. Okt 2009)

Nein, du machst 3 JARs.
Ein client.jar für den Client, ein server.jar für den Server und ein interface.jar für beide.

Auch wenn du nur 2 JARs hättest, würden die Methodenaufrufe natürlich trotzdem auf dem Server stattfinden. Die Implementierungsklassen werden ja vom Client nicht genutzt, ob die nun im Klassenpfad vorhanden sind oder nicht.


----------



## Sunbird (20. Jan 2010)

Bevor ich einen neuen Thread aufmache, nutze ich einfach mal den alten hier.

Erstmal vielen Dank für die Hilfe habs auch mittlerweile hinbekommen.

Ich habe folgende Situation und wollte einfach mal eure Meinungen dazu hören.

Mein Server.jar soll einmal gestartet werden und dann so lange laufen bis ich eine exit() Methode aufrufe die, die Remote-Objekte aus der Registry entfernt und nach Aufräumarbeiten den Server mit System.exit(0) stoppt.

Reicht es dazu einfach die Lease Time des DGC ausreichend hoch zu setzen? Der physikalische Server auf dem mein Server.jar läuft wird einmal am Tag neu gestartet.

Noch dazu habe ich eine generische ArrayList, die BenutzerObjekte enthält.
Dafür hab ich mir eine UserAgent Klasse geschrieben und per RMI kann darauf zugegriffen werden.
Sprich die Klasse, die meine main Methode enthält ist selber kein Remote Objekt, enthält aber solche.
Ist es sinnvoller meine "main-Klasse" auch als Remote Objekt zu deklarieren? Ich will natürlich sichergestellt haben das diese Klasse auch immer solange läuft bis ihr explizit mitgeteilt wird das sich das System runterfahren darf. Es darf auf keinen Fall von allein nach einer bestimmten Zeit herunterfahren. Zum Beispiel wenn der GC glaubt mein Objekt würde nicht mehr gebraucht.
Mein UserAgent Objekt ist innerhalb der main-Klasse als static deklariert.(Es sind auch nur statische Member und Methoden darin vorhanden) Verhindert allein das static, das diese Klasse erhalten bleibt oder wie erhält man sonst statische Referenzen auf Objekte in anderen Klassen?

Wie handelt ihr sowas?

Danke und Gruß


----------

