# RMI - the beginning



## Fabian030 (23. Mai 2009)

Ich mal wieder, nur mit einem anderen Programm.

Client/Server auf RMI Basis.

wenn ich server/client auf einem rechner starte, is allet supi.
starte ich vorher den rmiregistry in der konsole, spuckt mir der server folgenden fehler aus:
xception in thread "main" java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
	java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: programm.RemoteInterface


auf unterschiedlichen rechnern das ganze auszuführen, führte natürlich auch nur zu fehlern. server ließ sich dann zwar starten (nur ohne rmiregistry vorher aufzurufen), aber der client mochte natürlich den connect nicht :
Exception in thread "main" java.rmi.NotBoundException: http://192.168.220.103/MyServer
	at sun.rmi.registry.RegistryImpl.lookup(RegistryImpl.java:106)

---

im endeffekt will ich n programm aufm server starten (mit server-aufruf), strings vom client an den server übergeben, da die strings als eingaben für mein programm verwenden und das was das programm zurückgibt, wieder an den client senden um es dort auszugeben.


----------



## Fabian030 (23. Mai 2009)

lustig.
wenn ich die programme im eclipse aufrufe (ohne rmiregistry) kommt ja kein fehler.
wenn ich das ganze in der kommandozeile versuche zu kompilieren, kommen n paar fehler:
cannot find symbol
location class

sieht so aus, als könne er einige klassen nicht finden. path-variable wurde richtig gesetzt, java funktioniert. was läuft hier schief?


----------



## SlaterB (23. Mai 2009)

du musst entweder eine CLASSPATH Umgebungsvariable setzen oder -cp beim Programmstart angeben,
vergleiche
System.out.println(System.getProperty("java.class.path"));
von Eclipse und von Konsole aus


----------



## Fabian030 (23. Mai 2009)

die CLASSPATH variable hab ich gesetzt.
und zwar auf alle bin-Ordner meines programms
c:\blabla\projekt\bin\programm\
c:\blabla\projekt\bin\shop\
c:\blabla\projekt\bin\util\

hat auch nix gebracht. ^^


----------



## SlaterB (23. Mai 2009)

wie lauten denn die package-Namen der Klassen in welchen Verzeichnissen?
wenn du z.B. eine Klasse
programm.Hauptprogramm
unter 
c:\blabla\projekt\bin\programm\Hauptprogramm.class
liegen hast,
dann wäre 
c:\blabla\projekt\bin\programm\
im ClassPath genau falsch, es darf nur das Grundverzeichnis c:\blabla\projekt\bin\ aufgenommen werden,

wäre aber nicht der Hauch eines halben Problemes, wenn du einfach mal 
System.out.println(System.getProperty("java.class. path"));
von Eclipse aus gestartet anschauen würdest.. (falls ich richtig liege  )


----------



## Fabian030 (23. Mai 2009)

D:\Studium\Semester 2\workspace\AVS_Ubung2\bin\programm\ --> Server.class Client.class Interface.class
D:\Studium\Semester 2\workspace\AVS_Ubung2\bin\util\ --> sowas wie ne Tastatur.class
D:\Studium\Semester 2\workspace\AVS_Ubung2\bin\shop\ --> Kunde.class Artikel.class und anderes Gedöns

auf
D:\Studium\Semester 2\workspace\AVS_Ubung2\bin\ 
hatte ich den Classpath auch schon (vor dem Versuch, die Unterverzeichnisse der Packages in den CP zu sezten) und es führte zu dem gleichen Fehler. :/
PS: deine sysout getProperty spuckte aus: D:\Studium\Semester 2\workspace\AVS_Ubung2\bin ^^

ich setz das jetzt gleich nochmal.
BTW: wenn ich in der konsole %classpath% eingebe, sagt mir die konsole, dass der befehl "." nicht bekannt oder falsch geschrieben sei. in der classpath-variable der umgebungsvars steht --> ".;C:\blabla; ..."
was macht der "." da? ^^

edit: okok, ich hab das echo vergessen. doofes ich. aber trotzdem: was bedeutet da eigentlich der . ?? 
PS: classpath wie oben beschrieben geändert, gleicher fehler: kennt die anderen packages nicht, kann dadurch nix importieren und nichts funktioniert ...


----------



## SlaterB (23. Mai 2009)

> D:\Studium\Semester 2\workspace\AVS_Ubung2\bin\programm\ --> Server.class Client.class Interface.class

du verrätst nicht, in welchen Packages die Klassen in Java liegen, insofern sinnlose Information, 
denn dass das Verzeichnis nicht vollkommen leer ist, ist recht klar 

. steht fürs aktuelle Verzeichnis

> hatte ich den Classpath auch schon [..] und es führte zu dem gleichen Fehler. :/

kommt dann bei meinem Befehl die gleiche Ausgabe oder nicht?


----------



## Fabian030 (23. Mai 2009)

oooops 

ausgabe mit dem classpath nach deinen angaben:
D:\Studium\Semester 2\workspace\AVS_Ubung2\bin
ergo: das gleiche


und sorry @packages
die packages sind folgende:
programm --> D:\Studium\Semester 2\workspace\AVS_Ubung2\src\programm\
shop --> D:\Studium\Semester 2\workspace\AVS_Ubung2\src\shop\
util --> D:\Studium\Semester 2\workspace\AVS_Ubung2\src\util\
bzw halt die \bin\ ordner für die .class
???:L


----------



## SlaterB (23. Mai 2009)

und wie ist das nochmal mit allen Einzelprogrammen?
> wenn ich server/client auf einem rechner starte, is allet supi.
> starte ich vorher den rmiregistry in der konsole, spuckt mir der server folgenden fehler aus:

klingt nach insgesamt 3 Programm, haben alle davon die Ausgabe/ einen korrekten Classpath?
was ist überhaupt rmiregistry, ein Aufruf im Server oder ein eigenständiges Programm?
welche Projekte gibt es in Eclipse, welche Start-Konfigurationen, Build-Paths usw.
wo tritt die Exception auf, ist es eine eigene Exception oder nur die Ausgabe von der Übertragung eines anderen Programms?
besser anfangs ganz auf Netzwerk-Interaktion verzichten und jedes Programm für sich alle Klassen importieren lassen

viele viele Infos, Screenshots, Logs nötig, damit ich irgendwas kapiere,
vielleicht hast du aber auch Glück und jemand anders erklärt's kurz 


edit:
> wenn ich das ganze in der kommandozeile versuche zu kompilieren, kommen n paar fehler:

kompilieren ist ja noch mal ganz was anderes..


----------



## Fabian030 (23. Mai 2009)

 Aufgabe der RMI-Registry ist die Bereitstellung von Referenzen
auf Serviceobjekte
 die RMI Umgebung generiert bei der Anmeldung eines
Serviceobjekt an der rmiregistriy eine Objektreferenz
 diese enthält eine genaue Ortbeschreibung zur Lokalisierung des
Serviceobjekts:
- IP-Adresse
- Port
- ObjektID
 die Objektreferenzen werden unter einem kennzeichnenden
Namen an der Registry angemeldet
 ein Client holen sich über den Namen die Objektreferenz von der
Registry und kann damit auf das Serviceobjekt zugreifen
 die Registry steht als Hintergrundprozess bereit (rmiregistry.exe)

zum Vorgehen nach der Meinung eines Dozenten:
kompilieren - anmelden - nutzen
1. kompilieren des servers
2. kompilieren des clients
3. broker starten (rmiregistry.exe, is irgendwo im \bin der JDK)
4. server starten
5. client starten
(er meinte, wir sollten das von der kommandozeile aus tun - nunja ... sollten, nicht müssen)

in "programm" sind der client, der server und das remoteinterface.
in "shop" sind nur Klassen, die Methoden zum Zugriff und Speicher für Daten bereitstellen - den Shop betreffend, also: Kunde, Artikel (abstract), ArtikelEins, ArtikelZwei, BestellPositionen und Menu
in "util" sind nur Hilfeklassen: ein Kundennummerngenerator und eine Klasse Tastatur, die mir unterschiedliche Methoden zur Tastatureingabe stellt (Tastatur.liesChar, Tastatur.liesZahl, Tastatur.liesString etc. etc.)
ausgaben und ne main gibt's nur im server und im client.

ich wär ja schon froh, wenn ich jeden programm-mist auskommentieren würde und dann mal keine fehlermeldung beim verbinden auf verschiedenen rechnern erhalten würde ...
das müsste ja eigentlich klappen auch ohne den müll @shop/util
allerdings schimpft er dann immer noch wegen des interfaces, was ja im gleichen package wie server/client is.

???:L


----------



## Fabian030 (23. Mai 2009)

so, etwas quellcode
Server:

```
package programm;

import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
 
public class Server extends UnicastRemoteObject implements RemoteInterface {
	
    public Server() throws RemoteException {}
    
    
    public static void main(String[] args) throws RemoteException, MalformedURLException {
        Server objServer = new Server();
        
        Registry reg;
        try
        {
        	//Naming.rebind("MyServer", objServer);
        	reg = LocateRegistry.createRegistry(1099);
        }
        catch(java.rmi.RemoteException e)
        {
        	reg = LocateRegistry.getRegistry();
        }

        reg.rebind("MyServer", objServer);
        System.out.println(System.getProperty("java.class.path"));
        System.out.print(objServer);
        System.out.println("Server Ready" + "\n");
    }
}
```

Client:

```
package programm;

import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {
	static char auswahl = ' ';
	//String eingabe = "";
	
    public static void main(String[] args) throws NotBoundException, MalformedURLException, RemoteException {	
    	//Server serv = (Server) Naming.lookup("MyServer");
    	Registry registry = LocateRegistry.getRegistry(1099);
    	RemoteInterface ri = (RemoteInterface) registry.lookup("MyServer");
    }
}
```

RemoteInterface:

```
package programm;

import java.rmi.*;
import java.util.Date;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RemoteInterface extends Remote {
	//public String sayHello() throws RemoteException;
}
```


das sind die 3 RMI Hauptdinger, befreit von jedem zusätzlichen Code ...
konsole --> 
javac server.java
server.java:18: cannot find symbol
symbol: class RemoteInterface
public class Server extends UnicastRemoteObject implements RemoteInterface {

mit kleinem Pfeil auf das R von RemoteInterface

wenn ich server und client über eclipse starte, kommt kein fehler ...
wie bei der sache mit meinen code-schnipseln drin.

starte ich erst die rmiregistry.exe, dann gibt's das hier:
Exception in thread "main" java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
	java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: programm.RemoteInterface
	at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:396)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
	at sun.rmi.transport.Transport$1.run(Transport.java:159)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)
	at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
	at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359)
	at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
	at programm.Server.main(Server.java:34)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: programm.RemoteInterface
	at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
	at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:386)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
	at sun.rmi.transport.Transport$1.run(Transport.java:159)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassNotFoundException: programm.RemoteInterface
	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:247)
	at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:711)
	at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:655)
	at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:592)
	at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:628)
	at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294)
	at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:238)
	at java.ibjectInputStream.readProxyDesc(ObjectInputStream.java:1531)
	at java.ibjectInputStream.readClassDesc(ObjectInputStream.java:1493)
	at java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
	at java.ibjectInputStream.readObject0(ObjectInputStream.java:1329)
	at java.ibjectInputStream.readObject(ObjectInputStream.java:351)
	... 12 more


----------



## mvitz (23. Mai 2009)

```
javac programm/*.java
```

Anschließend kann man dort die rmiregistry starten.

Edit:

Bzw. wie und aus welchem Verzeichnis startest du denn die rmiregistry ? Die muss nämlich deine Klassen auch kennen.


----------



## Fabian030 (24. Mai 2009)

na die starte ich einfach aus irgendeinem verzeichnis heraus
über meine JAVA_HOME umgebungsvar findet er die ja ...
liegen tut se im \bin von der JDK die ich überall benutze. :/

edit: die "abgespeckte" version ließ sich jetzt kompilieren mit dem javac *.java ...
java server
führt dann allerdings zu nem fehler: 
Exception in thread "main" java.lang.NoClassDefFoundError: server/java

edit: kommt wohl davon ... wenn man sonst immer nur mit IDEs arbeitet. :/ - sind wohl alle imports, die das programm braucht und die man sich jetzt per hand zusammensammeln soll?


----------



## SlaterB (24. Mai 2009)

heißt die Klasse nicht Server mit großem S und liegt in einem package?
also
java programm.Server
und das Verzeichnis, von dem aus das Kommando aufgerufen wird (bin-Verzeichnis) + der ClassPath sind wie immer extrem wichtig


----------



## mvitz (24. Mai 2009)

Die rmiregistry muss den Classpath kennen. Entweder deine Klassen in den Classpath aufnehmen:

Unter Linux:
export CLASSPATH=/path/to/classes

Unter Win weiß ich gerade nicht.

Oder aus dem Ordner: /path/to/classes die rmiregistry starten.


----------



## Fabian030 (24. Mai 2009)

SlaterB hat gesagt.:


> heißt die Klasse nicht Server mit großem S und liegt in einem package?
> also
> java programm.Server
> und das Verzeichnis, von dem aus das Kommando aufgerufen wird (bin-Verzeichnis) + der ClassPath sind wie immer extrem wichtig




ich hab jetzt, um das kompilierungsproblem zu umgehen, alle klassen in das default-package gepackt - und siehe da: javac *.java funktioniert auf einmal.
vorher ging das nur bei den klassen, die keinen import aus eigenen packages hatten. ???:L 
nunja, der fehler kam auch beim großen S

@habi: ich hab den classpath in den umgebungsvariablen gehabt. aber ich werd dann mal die rmiregistry aus dem classpath verzeichnis aus starten.


edit: hat nix gebracht.
wenn ich die rmiregistry zuerst starte und dann den server in eclipse, scheitert er an dem try-teil und rutscht ins catch
wenn ich die rmiregistry nicht starte, kommt er ins try und tut was er soll.
allerdings konnt ich dann bisher auch nich von nem anderen rechner auf den server zugreifen. nur wenn ich den client aufm gleichen PC laufen ließ.

```
try
        {
        	//Naming.rebind("MyServer", new Server());
        	reg = LocateRegistry.createRegistry(1099);
        }
        catch(java.rmi.RemoteException e)
        {
        	e.printStackTrace();
        	//Naming.rebind("MyServer", objServer);
        	reg = LocateRegistry.getRegistry();
        }
```


edit: der client connected nicht mit dem hinweis: Connection refused.
kann das eines dieser rechte-probleme sein? wo geb ich denn die server.policy bzw client.policy dateien an?


----------



## Fabian030 (24. Mai 2009)

so, fehlermeldung beim starten des servers unter eclipse, wenn ich erst die rmiregistry aufrufe:

java.rmi.server.ExportException: Listen failed on port: 1099; nested exception is: 
	java.net.SocketException: Unrecognized Windows Sockets error: 0: JVM_Bind
	at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:312)
	at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:218)
	at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:393)
	at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:129)
	at sun.rmi.server.UnicastServerRef.exportObject(UnicastServerRef.java:190)
	at sun.rmi.registry.RegistryImpl.setup(RegistryImpl.java:92)
	at sun.rmi.registry.RegistryImpl.<init>(RegistryImpl.java:78)
	at java.rmi.registry.LocateRegistry.createRegistry(LocateRegistry.java:186)
	at Server.main(Server.java:35)

kann damit jemand was anfangen? :/


edit: aaaalso ich hab den port einfach mal auf 1112 gesetzt, rmiregistry gestartet, den server gestartet unter eclipse - und siehe da: er läuft.
probelm client ... ^^

```
RemoteInterface ri = (RemoteInterface) registry.lookup("//192.168.220.101/MyServer");
```
die zeile wirft mir einen fehler. der server läuft auf der .101 mit dem namen MyServer ...
und zwar: java.rmi.NotBoundException: //ip/MyServer

???:L


----------

