# RMI-Problem: Nur ein Server start möglich.



## spyboot (23. Sep 2008)

Hallo!


Ich habe via rmi eine Client-Server-Applikation geschrieben und gleich als erstes dass Port-Forwarding (war bei meinem Router unter dem Punkt "Virtual Server" zu finden) eingerichtet. 
Dass Funktioniert auch alles wunderbar nur dass der Server beim zweiten Start nicht mehr Funzt (außer wenn ich meinen Computer neustarte)!
Ich hab den Ablauf mal als Liste aufgeschrieben:

1. Server Start
2. Client Start
3. Client bekommt eine Verbindung
4. Ich beende den Server
5. Server Start
6. Client Start
7. Client bekommt *keine* Verbindung (Connection Timed out)
8. Neustart des Computers
9. Server Start
10. Client Start
11. Client bekommt eine Verbindung
12. ...

Hatt einer ne Idee? Ich vermute (und korrigiert mich wenn ich wiesooft danebenliege) dass irgendein rmi Prozess mit System.exit(0) nochnicht beendet ist und immernoch Daten für dass (bereits beendete) programm empfängt dass aber nicht mehr antworten kann!
Hier noch ein Paar Client und Server Snippets:

Server:

```
...

LocateRegistry.createRegistry(1099);
final Registry registry = LocateRegistry.getRegistry();
registry.rebind("client", new server());

...

try{
    registry.unbind("client");
} catch (NotBoundException e){
    ...
}

System.err.println("Server beendet");
System.exit(0);
```

Client:

```
//Ip ändert sich muss sie nach jedem Neustart neu einstellen
rmiverbindung = (client) Naming.lookup("rmi://**.***.**.***:1099/client");
```


----------



## tuxedo (23. Sep 2008)

RMI hintern Routern ist äußerst sch**sse. Da beisst du dir die Zähne dran aus wenn du auch noch Callbacks verwendest und von CGI und Co. nicht die Ahnung hast (und selbst wenn, das ist bei RMI sehr schlecht dokumentiert. Frei nach dem Motto "sowas macht ja keiner").

Kennst du SIMON schon? Schau mal in meine Signatur.

- Alex


----------



## spyboot (23. Sep 2008)

^^nein SIMON kannte ich nicht aber ich habs mir gleich ma angesehen allerdings ist mein programm schon sehr komplex und ich würde ungerne alles umschreiben müssen deshalb wäre es schön eine andere Lösung die auf rmi basiert zu finden.

-danke


----------



## tuxedo (24. Sep 2008)

Nach dem zweiten Serverstart könntest du mal mit "telnet <serverip> 1099" und "telnet <serverip> 1098" schauen ob die notwenidgen Ports überhaupt offen sind und antworten. 

Am besten dann noch via "netstat -ban" am Server mal schauen auf welchen Ports er lauscht. 

Dann weisst du immerhin schon mal ob der Dienst läuft oder nicht.

- Alex


----------



## spyboot (24. Sep 2008)

Wieso Telnet <serverp> *1098*? Ich benutz doch nur Port 1099!


----------



## tuxedo (25. Sep 2008)

Ja, vermutlich wirst du den Activator nicht benutzen. Der läuft auf Port 1098 (siehe: http://de.wikipedia.org/wiki/Remote_Method_Invocation). Wichtiger ist für dich dann 1099 ..

- Alex


----------



## spyboot (25. Sep 2008)

Telnet kommt zu dem Selben ergebnis: Connection timed out... (Telnet meint keine verbindung zum host auf port 1099 möglich). Aber sobald ich stadt der ip localhost schreibe funzt alles wieder wunderbar.


----------



## tuxedo (26. Sep 2008)

?? D.h. du führst Telnet auf dem selben Rechner aus, auf dem auch die RMI Registry läuft? Wo liegt dann der tiefere Sinn des Portforwardings? Okay, lassen wir das mal bei Seite:

Wenn du Telnet auf der Maschine ausführst, auf der auch der RMI Server läuft, und du nur mit "localhost", bzw. 127.0.0.1 eine Verbindung bekommst, dann hat sich die Registry offensichtlich nicht an die IP deiner Netzwerkkarte gebunden, sondern ausschließlich ans Loopback Interface. 

Aber vielleicht schilderst du nochmal detailiert was wo auf welcher Maschine läuft, wo der Router sich in diesem Konstrukt befindet etc.

- Alex


----------



## spyboot (26. Sep 2008)

Ob ich nun auf meinem lokalen Rechner mit der ip und nicht mit localhost das Programm aufrufe oder nicht auf einem Rechner innerhalb meines netztwerkes ist doch egal oder?


----------



## tuxedo (26. Sep 2008)

Nein, ist es nicht. Stichwort Router/Firewall/Proxy etc.


----------



## spyboot (26. Sep 2008)

dann wäre es möglich das dass die fehlerquelle ist? Werds glech ma mit nem anderen pc testen.


----------



## tuxedo (26. Sep 2008)

Teste am besten Client und Server nochmal auf einem PC... Wenn das wirklich geht, erweitere das ganze Stück für Stück und teste immer bis der Fehler auftaucht. Dann weisst du exakt wo das Problem liegt.
- Alex


----------



## spyboot (2. Okt 2008)

Mit Localhost klappt alles.
Mit Ip geht es nicht vom eigenen, nicht von einem anderen Pc im Netztwerk und nicht von einem entfernten Computer!

Ich glaube mir wird die ganze sache jetzt zuviel und ich steige doch auf SIMON um aber ich habe dass gefühl dass SIMON noch ziehmlich in den Startlöchern steht und deshalb noch nicht so stabiel läuft (dem Forum zu urteilen).
Ist SIMON von der Struktur her ähnlich wie RMI aufgebaut sodass im Prinzip die Befehle nur anders heissen?

Wäre nett wenn mir jemand auf meine Frage eine Antwort geben könnte evt. sogar ein Bespiel liefern.

-Danke


----------



## spyboot (2. Okt 2008)

^^Ich habe gerade festgestellt dass es stadt einem nun keinen erfolgreichen Verbindungsaufbau mit Ip gibt.


----------



## tuxedo (3. Okt 2008)

Jepp, SIMON ist RMI recht ähnlich, jedoch nicht 1:1 Befehlskompatibel. 

Zu den Startlöchern: Naja. Das ist Ansichtssache. Wenn du einen Blick ins Changelog wirfst wirst du dir ein besseres Bild machen können. Auch ein Blick in den Bugtracker hilft dabei.

Ein Projekt kann natürlich nicht besser werden wenn es niemand benutzt. Bisher hab ich drei mir bekannte Benutzer die mir regelmäßig Feedback geben um SIMON zu verbessern. 

Da die meisten RMI nur mit den Basisfunktionen benutzen, ist ein Umstieg auf SIMON wohl nicht weiter schwer oder risikoreich. 

Was macht denn deine Client-Server-Anwendung?


----------



## spyboot (3. Okt 2008)

Es soll eine Applikation werden die es erlaubt direkt über dass Internet Dateien zu verschicken Außerdem wird ein Chat integriert sein und sie wird die Möglichkeit haben (ähnlich ACDSee) einen Computer vernzusteuern (dazu setzte ich auf dem Client Computer ein VBScript ein um Mausclicks und Tastaturengaben zu simmulieren). 
Also muss sie (ca. 5 mal die Sekunde) ein bild von 800 * 600 pixeln über dass Internet verschicken. Ich habe schon in RMI fesgestellt das mann nicht einfach bilder als Rückgabewert verschicken kann also habe ich mir die Bytes aus dem Bild geholt und verschickt.


----------



## tuxedo (3. Okt 2008)

Chat mit SIMON: Kein Problem

Dateien verschicken:
Mit SIMON: Keine gute Idee
Mit RMI: Keine gute Idee

Einen Rechner Remote steuern ala VNC: 
Mit SIMON: Keine gute Idee
Mit RMI: Ebenfalls keine gute Idee

5mal/sek ein 800x600 Bild übermitteln:
Mit SIMON: Keine gute Idee
Mit RMI: Keine gute Idee

Grund für "keine gute Idee":

Sowohl SIMON als auch RMI basieren auf Reflection. Hier wird zur Laufzeit entschieden welche Klasse geladen werden muss, welche Methode aufgerufen werden muss etc. Dieses "hintenrum" und "zur compilezeit nicht wissen", kostet zur Laufzeit deutlich Zeit.

Sowohl das Dateien verschicken, als auch das Remotesteuern eines Desktops, was undheimlich viele Methodenaufrufe bedarf, ist deshalb nicht performant. Es geht dabei einfach zu viel Zeit drauf zu erkennen welche Methode welcher Klasse aufgerufen werden muss und das dann auch durchzuführen. 

Einen Desktop Remote Steuern mit Java: Die Serverseite gibt es schon. Nennt sich VNC Server (google mal nach Real VNC oder Tight VNC). Auf der Clientseite gibt es zahlreiche VNC Clients die man in die eigene Anwendung einbauen kann (von TightVNC weiß ich dass es da die Sourcen gibt, hab ich sogar schonmal verwendet).
Dateien verschicken: Da bist du mit einer einfachen Socketverbindung wesentlich schneller. Da musst du zwar auch häufig Methoden aufrufen um die Byte-Pajete zu verschicken, aber das ganze Reflection geraffel plus der Protokolloverhead durch RMI oder SIMON fällt weg. 

Nebenbei gesagt: DIverse VNC Implementierungen erlauben es schon Dateien zwischen VNC Server und Client auszutauschen. Alles was du noch bräuchtest wäre dann die Charfunktion.

Tipp: Schau dir Tight VNC an, nimm den Client und erweiter diesen um eine Chat-Funktion (die kann dann von mir aus auf SIMON basieren).

Aber die ganze FUnktionalität auf SIMON oder RMI abzubilden halte ich für keine gute Idee. Du wirst Performanceprobleme ohne Ende bekommen. Reflection und Co. wurde nunmal nicht erfunden um große Datenmengen (Screenscraping und FIletransfer gehören da dazu) zu übermitteln.

Sorry für die schlechte Nachricht.

- Alex


----------



## spyboot (3. Okt 2008)

Ich hab gerade mal Nachgerechnet:

800*600/1024*5=2343,75 Kbyte/sec

^^Ich glaube du hast recht dass dass ("ein wenig") zu langsam wäre...

Wie sieht es nun aus mit einem Chat und übertragen von Arrays und Listen?

Wielange dauert es ungefähr eine String Array a 10 Zeichen pro Feld mit einer Größe von 30*30 Feldern zu übertragen?

Dass wäre dann sozusagen die erste übertragung der Userliste dann könnte mann dass mit "user1>quit" und "user2>join" Managen und damit bandbreite Sparen.

Wie siht es eigentlich bei Java mit Microfonen aus? Kann mann dass als Stream auslesen? Damit mann sich über Headseat unterhalten kann? Ich weiß dass es bereits Software wie Teamspeak2 gibt aber dass ist (wenn mann einen Server erstellt) genausowenig Routerfreundlich.


----------



## tuxedo (3. Okt 2008)

Problem ist nicht die Datenmenge, sondern die Anzahl von Methodenaufrufen um die Datenmenge zu bewältigen.

Du kannst sehr wohl einen 1920x1200 Desktop übers Netz übertragen, aber eben nicht mit RMi oder SIMON, sondern mit einem entsprechend schlanken Protokoll mit einer passenden Komprimierung. 

D.h. Chat und Co. stellen kein Problem dar, da für eine Chatnachricht ja kein 1000 Methodenaufrufe notwendig sind. 

Audio mit Java geht. Dafür gibts die Java Sound API. Damit kannst du Mikrofone benutzen etc.
ABER: Für Einsteiger ist das wohl nix. Und schon garnix wenns drum geht auch nur Ansatzweise sowas wie Teamspeak zu bauen. Kleines Beispiel: Audiokonferenzsysteme ala Teamspeak war das Hauptthema meiner Diplomarbeit. In 5 Monaten hatte ich eine primitive Client/Server Anwendung mit eigenem primitiven Protokoll und gleicher Sprachkomprimierung wie Teamspeak. Ich schätze um etwas vergleichbares wie TS zu bauen braucht man, mit dem passenden KnowHow locker 1 Jahr. Und dann ist es noch nicht Fehlerfrei und hübsch...

>> Ich weiß dass es bereits Software wie Teamspeak2 gibt aber dass ist (wenn mann einen Server erstellt) genausowenig Routerfreundlich.

Das ist quatsch. Wozu gibts Portforwarding? Für private Zwecke (also wenn man keinen Server hat), tut's ja auch Skype und Co. 
Für alles andere sollte eh ein vernünftiger Server her.

- Alex


----------



## spyboot (3. Okt 2008)

Gibt es irgendwo ein gutes Simon Tutorial oder nur die Englische Doku?


----------



## tuxedo (3. Okt 2008)

Schau dass du das Codesample (http://root1.de/node/8) ans laufen bekommst. Das zeigt schon fast die ganze Funktionalität. Ein Tutorial braucht man da nicht. Und wenn du RMI schon benutzt hast, wird dir einges am Codesample sogar vertraut vorkommen.

Viel englischen Text gibt es da nicht. Wenn du Fragen hast, kannst du diese auch im SIMON Forum stellen (auf deutsch).

- Alex


----------



## spyboot (7. Nov 2008)

sorry dass ich den Thread nochmal ausgrabe!

Ich hab jetzt mal ein Bisschen mit dem Codesample herumexperimentiert und alles so abgewandelt dass ich einen String übergebe aber ich bekomme jedesmal folgende Fehlermeldung:


```
07.11.2008 17:28:10 de.root1.simon.ReadEventHandler run
WARNUNG: class not found on [[client|connectedTo=127.0.0.1,localport=54398,remoteport=2000]interestOps=OP_READ (1),readyOps=OP_READ (1)]: ServerInterface
Exception in thread "main" de.root1.simon.exceptions.SimonRemoteException: class not found on [[client|connectedTo=127.0.0.1,localport=54398,remoteport=2000]interestOps=OP_READ (1),readyOps=OP_READ (1)]: ServerInterface
	at de.root1.simon.ReadEventHandler.run(ReadEventHandler.java:218)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
```

mein programmcode:


```
import de.root1.simon.Simon;
import de.root1.simon.exceptions.EstablishConnectionFailed;
import de.root1.simon.exceptions.LookupFailedException;
import de.root1.simon.exceptions.SimonRemoteException;


 
public class Client {
 
	public static void main(String[] args) throws SimonRemoteException, EstablishConnectionFailed, IOException, LookupFailedException {
 
	
 
		// 'lookup' the server object
		ServerInterface server = (ServerInterface) Simon.lookup("localhost", 2000, "server");
 
		// use the serverobject as it would exist on your local machine
		server.login("hi");
 
		
 
		// and finally 'release' the serverobject to release to connection to the server
		Simon.release(server);
 
	}
 
}


import java.io.IOException;
import java.net.UnknownHostException;

import de.root1.simon.Registry;
import de.root1.simon.Simon;
import de.root1.simon.exceptions.NameBindingException;


 
public class Server {
 
	public static void main(String[] args) throws NameBindingException, UnknownHostException, IOException {
 
		// create the serverobject
		ServerInterfaceImpl serverImpl = new ServerInterfaceImpl();
 
		// create the server's registry ...
		Registry registry = Simon.createRegistry(2000);
 
		// ... where we can bind the serverobject to
		registry.bind("server", serverImpl);
 
		System.out.println("Server up and running!");
 
	}
 
} 




import de.root1.simon.exceptions.SimonRemoteException;


public class ServerInterfaceImpl implements ServerInterface {
 
private static final long serialVersionUID = 1L;
 
	public void login(String t) throws SimonRemoteException {
		System.out.println(t);
	}
 
} 





 
import de.root1.simon.SimonRemote;
import de.root1.simon.exceptions.*;

 
public interface ServerInterface extends SimonRemote {
 
	public void login(String t) throws SimonRemoteException;
 
}
```


Bin mal wieder planlos... :shock:


----------



## tuxedo (8. Nov 2008)

Das Interface des Servers muss beim Client im Classpath sein ....

Oder um's genauer zu sagen:

Alle Remoteobjekte, die du auf Clientseite benutzen willst, haben ein "public interface .... extends SimonRemote". Und jede dieser Interfaceklassen muss der Client in seinem Classpath vorfinden.

Die dazugehörige Implementierungsklasse darf natürlich auf dem Server verbleiben (bzw. sollte/muss, aus Sicherheitsgründen).

- Alex


----------



## spyboot (11. Nov 2008)

hab ich doch oder?


----------



## tuxedo (11. Nov 2008)

Offensichtlich nicht. Du hast zwar Interfaces, aber laut dem Classloader sind die nicht im Classpath zu finden...

- Alex


----------



## spyboot (11. Nov 2008)

Aber ich habe alles so wie es da steht und (bei Eclipse) alles im selben Ordner!


----------



## tuxedo (12. Nov 2008)

Dann sei doch so gut und schick mir mal das Projekt gezipped (sieht ja nach dem Sample aus...) per Email. Dann kann ich genauer drauf schauen.

- Alex


----------



## spyboot (12. Nov 2008)

Ok bin grad nicht Zuhause aber sobald ich da bin (so gegen 16:00)
schick ich dir dass Projekt.
Aber eigentlich ist alles genau so wie es da steht nur eben in einzelnen .java Datein.


----------



## tuxedo (12. Nov 2008)

Hab eben per copy&paste alle gezeigten Klassen und Interfaces in ein leeres Projekt gezogen. Funktioniert prima. Sowohl mit SIMON 0.2, als auch mit SIMON 0.3 ALPHA ....

Warte also auf deinen Projektordner.

Gruß
Alex


----------



## spyboot (12. Nov 2008)

an welche E-mail adresse soll ich den die E-Mail schicken die von root1.de->contakt?


----------



## tuxedo (12. Nov 2008)

jupp. wäre aber klasse wenn du die Emailadresse aus deinem post für EmailCrawler und SpamBots nicht allzuleicht zugänglich machst ;-)

- Alex


----------



## tuxedo (12. Nov 2008)

Du hast Post ...

- Alex


----------



## spyboot (12. Nov 2008)

Also:

-Ich hab alles mit Eclipse Gestartet
-Alle Datein liegen im selben verzeichnis
-ich habe SIMON.jar über installed jres>externe jars hinzufügen "Installiert"

Muss ich nochwas hinzufügen?


----------



## spyboot (12. Nov 2008)

Ok es klappt nachdem ich die jar so hinzugefügt hatte wie du es beschrieben hast.

Danke für den Aufwand und alles andere!

-Spyboot


----------



## tuxedo (12. Nov 2008)

Nein, mehr eigentlich nicht.

Das von mir zurückgeschickte Projektverzeichnis sollte "out of the box" laufen. Wenn nicht, dann ist mit deinem Eclipse was schief gewickelt.

Vorschlag:

Entpacke/Installiere Eclipse nochmal neu in ein Verzeichnis. Starte dann dieses neue Eclipse und importiere das von mir geschickte Projektverzeichnis. Dann startest du den Server, gefolgt vom Client und berichtest was sich tut.

Wenn auch das nicht geht bin ich vorerst am Ende mit meinem Latein. Kann dann eigentlich nix mit SIMON an sich zu tun haben. Hab es hier auf verschiedenen XP Rechner, unter Debian Linux, OpenSuSE Linux, sowie unter MacOS im Einsatz. Jeweils ohne Probleme. Überall ist Java 6 im Einsatz, alles zwischen Update 3 und 10 ist vertreten. XP hab ich sowohl in Englisch auls auch Deutsch und teilweise mit SP2 oder SP3. Denke das deckt alle gängigen Varianten ab...

- Alex


----------



## tuxedo (12. Nov 2008)

Sorry, hab eben erst festgestellt, dass ich vergessen hatte die file an die email anzuhängen... *schäm*

Abe rist schon etwas mysteriös... 
Zum einen konnte alles aus der SIMON.jar geladen werden (sonst wäre die Meldung nicht gekommen die von einer SIMON Klasse geworfen wird), und zum anderen ist dann eine eigene Klasse/Interface von dir nicht im Classpath.

Aber gut dass es jetzt bei dir läuft. Und jetzt weißt du auch wie du mit externen Libs am besten umgehst ;-)

Gruß und viel Spass mit SIMON
- Alex

P.S. Version 0.3 ist auf dem Vormarsch .. Also hin und wieder mal auf der Projektseite vorbeischauen ....


----------



## spyboot (12. Nov 2008)

Ähm ein Problem wär da noch: Zuerst hatt es wieder nur lokal geklappt weil ich als port forwarding den lokalen port 2000 und public port 2000 hatte.
dann habe ich festgestellt dass SIMON immer einen anderen lokalenpoert benutzt zb 5007 dann hab ich in meinem router die lokalen ports 1000-10000 benutzen lassen und dann gings. Leider ist dass wohl nur sehr ungenau und blockiert ein par andere anwendungen also würde ich gerne wissen welche lokalen Ports SIMON verwendet (zb. 5000-5100) damit ich weiß welche portspanne ich vowarden soll.


----------



## tuxedo (12. Nov 2008)

SIMON verhält sich da wie Firefox, Internetexplorer und jede andere Anwendung die Sockets benutzt: Die ausgehenden Ports des Clients werden vom Betriebssystem frei gewählt. Diese zu beschränken wäre stumpfsinnig. Anders ist es mit den Serverports...

Wenn du einen Simon-Server hinter deinem Router betreiben willst, so dass dieser übers Internet erreichbar ist, so musst du nur den Port 2000 des Servers via Portforwarding am Router freigeben. Mehr nicht. Der Port auf Clientseite ist hierbei egal.

- Alex


----------



## spyboot (13. Nov 2008)

Ich hab bei meinem Router einfach mal an ein paar sachen rumgestellt die ich nicht verstehe und dann gings!


----------



## tuxedo (13. Nov 2008)

Ich skizzier das mal:


```
[Server, IP 192.168.0.2, SIMON auf Port 2000] 
  |
  |
  |
[Router interne IP: 192.168.0.1, ext. IP:  200.200.200.2]
  |
  |
  |
[Client, IP 100.100.100.1]
```

Alles was du jetzt tun must, ist im Router unter Portforwarding einzustellen:

Transport: TCP
Eingehender Port: 2000
Zielport: 2000
Ziel-IP: 192.168.0.2

Heisst nichts weiter als:
Router: "Alle Pakete, die ich auf meiner externen IP 200.200.200.2 auf dem eingehenden Port 2000 rein bekomme, leite ich weiter an die Ziel-IP 192.168.0.2 an den ZielPort 2000".

Mehr nicht. Am Client verbindest du dich dann, gemäß dem Beispiel mit IP 200.200.200.2 und Port 2000

Adaptiere das einfach auf deine IPs und Ports und fertig. Dann klappt's auch mit dem Nachbar ;-)

- Alex


----------



## spyboot (13. Nov 2008)

^^ Danke für die Antwort bin jetzt um einiges Schlauer :idea:


----------

