Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

RMI mit Applet als Client

0 views
Skip to first unread message

Achim Hilwers

unread,
Jun 7, 2003, 4:11:29 PM6/7/03
to
Hallo!

Ich habe mittlerweile ein Verständnisproblem, bei dessen Klärung mir
vielleicht einer von Euch helfen kann. :-)

Ich habe einen RMI-Server und ein Applet als Client - es handelt sich um ein
Spiel. Das Client Applet verbindet sich schön mit dem Server und dieser
registriert auch wuderbar diese Verbindung. Nun versucht dieser, ein
Spielfeld zu erzeugen und das dem Client mittels RMI-Callback
zurückzuliefern. Dies scheint nicht zu klappen. Der Server sagt gar nichts,
aber auf dem Client bekomme ich in dem Moment eine AccessControlException
mit der IP des Clients.

Nach einiger Sucherei in den Newsgroups glaube ich nun in Erfahrung gebracht
zu haben, daß es - selbst mit einem signierten Applet - nicht möglich ist,
vom Server aus eine Socket-Verbindung zu einem entfernten Client
aufzunehmen, ohne daß der User an seinen Policy-Einstellungen herumdreht.

Wenn dem so ist, dann frage ich mich doch, wie es bspw. bei den diversen
IRC-Applets oder sonstigen Java-Chats möglich ist - die werden doch auch
eine Socket-Verbindung aufbauen, um etwas vom Server empfangen zu können,
oder sehe ich das falsch?

Ich bin mittlerweile am Verzweifeln. Kann mir jemand sagen, warum das in
diversen Chats klappt, ohne daß man als Benutzer seine Policies einstellen
muß, bei mir aber nicht?

Gruß!

Achim

Marcel Stör

unread,
Jun 7, 2003, 4:55:25 PM6/7/03
to

IMHO vermischst du da etwas: Socket != RMI.
RMI callbacks funktionieren über das Internet nicht. Solange du dich im
eigenen Netz befindest, sollte das gehen (Beispielcode dazu könnte ich dir
liefern).

Gruss
Marcel

michael paap

unread,
Jun 7, 2003, 5:11:21 PM6/7/03
to
Marcel Stör wrote:

> RMI callbacks funktionieren über das Internet nicht. Solange du dich im
> eigenen Netz befindest, sollte das gehen (Beispielcode dazu könnte ich dir
> liefern).

Bitte?

Was ist denn der Unterschied zwischen "Internet" und "eigenem Netz", mal
abgesehen von unterschiedlichen IP-Bereichen?

Gruß,
Michael

--
Sollte ausnahmsweise eine Mail-Antwort auf ein Posting vonnöten sein,
bitte folgende Adresse verwenden: newsreply@<Absender-Domain>.

michael paap

unread,
Jun 7, 2003, 5:11:51 PM6/7/03
to
Marcel Stör wrote:

> RMI callbacks funktionieren über das Internet nicht. Solange du dich im
> eigenen Netz befindest, sollte das gehen (Beispielcode dazu könnte ich dir
> liefern).

Bitte?

Was ist denn der Unterschied zwischen "Internet" und "eigenem Netz", mal

abgesehen von unterschiedlichen IP-Addressbereichen?

Frank Seidinger

unread,
Jun 7, 2003, 6:06:19 PM6/7/03
to
Achim Hilwers wrote:
> Ich habe einen RMI-Server und ein Applet als Client - es handelt sich
> um ein Spiel. Das Client Applet verbindet sich schön mit dem Server
> und dieser registriert auch wuderbar diese Verbindung.
Soweit ist das schon in Ordnung

> Nun versucht
> dieser, ein Spielfeld zu erzeugen und das dem Client mittels
> RMI-Callback zurückzuliefern. Dies scheint nicht zu klappen. Der
> Server sagt gar nichts, aber auf dem Client bekomme ich in dem Moment
> eine AccessControlException mit der IP des Clients.

Warum lieferst du dem Client das Spielfeld nicht als Rückgabewert einer
Methode des Servers. Dann brauchtst du keinen Callback und alles ist in
Ordnung.

> Nach einiger Sucherei in den Newsgroups glaube ich nun in Erfahrung
> gebracht zu haben, daß es - selbst mit einem signierten Applet -
> nicht möglich ist, vom Server aus eine Socket-Verbindung zu einem
> entfernten Client aufzunehmen, ohne daß der User an seinen
> Policy-Einstellungen herumdreht.

Selbst das sollte gar kein Problem sein. Dein Server sollte nämlich für
den Callback gar keine Verbindung zu Client aufmachen. Denn eine
IP-Verbindung zwischen Server und Client besteht schon. Und die hat der
Client ja beim Verbindungsaufbau aufgemacht. IP wird ja hier nur als
Transportprotokoll genommen. Darüber wird der RMI-Channel gelegt und der
sollte für beide Richtung gehen.

> Wenn dem so ist, dann frage ich mich doch, wie es bspw. bei den
> diversen IRC-Applets oder sonstigen Java-Chats möglich ist - die
> werden doch auch eine Socket-Verbindung aufbauen, um etwas vom Server
> empfangen zu können, oder sehe ich das falsch?

Nein, die arbeiten genau so. Es muss bei dir also etwas anderes nicht in
Ordung sein. Deine Interfaces und die Serverimplementierung könnten hier
hilfreich sein.

--
Wir müssen heute 14-Jährige unterhalten, die keine Lebenserfahrung,
keine Bildung und keinen Geschmack haben [John Cleese über Hollywoods
bevorzugte Zielgruppe]


Frank Seidinger

unread,
Jun 7, 2003, 6:08:55 PM6/7/03
to
michael paap wrote:
> Bitte?
>
> Was ist denn der Unterschied zwischen "Internet" und "eigenem Netz",
> mal abgesehen von unterschiedlichen IP-Addressbereichen?
So hübsche Sachen, wie Firewalls, NAT, Router, etc. Nur wenn du eine
transparente Verbindung mit den für RMI und die Registry benötigten
Ports hast, sind Internet und lokal identisch.

michael paap

unread,
Jun 7, 2003, 6:23:52 PM6/7/03
to
Frank Seidinger wrote:

> So hübsche Sachen, wie Firewalls, NAT, Router, etc. Nur wenn du eine
> transparente Verbindung mit den für RMI und die Registry benötigten
> Ports hast, sind Internet und lokal identisch.

Ach! [TM]

> Nur wenn du eine
> transparente Verbindung mit den für RMI und die Registry benötigten
> Ports hast, sind Internet und lokal identisch.

Ich weiß. Nur trifft das letzlich für *alle* Dienste zu.

Davon wird die Aussage "RMI callbacks funktionieren über das Internet
nicht." nicht weniger sinnfrei. Mit der gleichen Logik kann ich
behaupten, HTTP funktioniere nur im lokalen Netz, weil gerade mein
Router kaputt ist. ;-)

michael paap

unread,
Jun 7, 2003, 6:33:24 PM6/7/03
to
Marcel Stör wrote:

> RMI callbacks funktionieren über das Internet nicht. Solange du dich im
> eigenen Netz befindest, sollte das gehen (Beispielcode dazu könnte ich dir
> liefern).

Bitte?

Was ist denn der Unterschied zwischen "Internet" und "eigenem Netz", mal
abgesehen von unterschiedlichen IP-Addressbereichen?

Gruß,

Achim Hilwers

unread,
Jun 7, 2003, 6:43:05 PM6/7/03
to
Hallo!

> Warum lieferst du dem Client das Spielfeld nicht als Rückgabewert einer
> Methode des Servers. Dann brauchtst du keinen Callback und alles ist in
> Ordnung.

An der Stelle könnte ich es auch mittels Rückgabewert machen - da hast Du
natürlich Recht. Allerdings muß ich spätestens dann Client-Methoden
aufrufen, wenn einer der Clients einen Spielzug macht - der muß ja an die
anderen Clients delegiert werden. Ich möchte ja nicht von jedem Client aus
ständig den Server fragen, ob ein neuer Zug anliegt. :-)

> Nein, die arbeiten genau so.

Gut, dann weiß ich wenigstens, daß ich nicht ganz auf dem Holzweg bin. :-)

> Es muss bei dir also etwas anderes nicht in
> Ordung sein. Deine Interfaces und die Serverimplementierung könnten hier
> hilfreich sein.

Ich werde einmal sehen, ob ich irgendwo den Fehler entdecken kann. Hier bei
mir im lokalen Netzwerk funktioniert alles wunderbar. Ich werde Morgen mal
ein paar sinnvolle Code-Fragmente heraussuchen und hier posten. Die gesamte
Implementierung wäre etwas zu umnfangreich für die Newsgroup, denke ich.

Gruß!

Achim

Marcel Stör

unread,
Jun 8, 2003, 4:04:28 AM6/8/03
to
michael paap wrote:
> Marcel Stör wrote:
>
>> RMI callbacks funktionieren über das Internet nicht. Solange du dich
>> im eigenen Netz befindest, sollte das gehen (Beispielcode dazu
>> könnte ich dir liefern).
>
> Bitte?
>
> Was ist denn der Unterschied zwischen "Internet" und "eigenem Netz",
> mal abgesehen von unterschiedlichen IP-Addressbereichen?

Sorry, dass ich euch mit meiner Formulierung ein bisschen verwirrt habe.
Hätte mich gestern Abend vielleicht 100% auf die Bewirtung der Gäste
konzentrieren sollen ...;-)

Auf jeden Fall schreibt Achim zum Schluss, ich zitiere: "Hier bei


mir im lokalen Netzwerk funktioniert alles wunderbar".

Offensichtlich scheinem ihm tatsächlich "So hübsche Sachen, wie Firewalls,
NAT, Router" (O-Ton Frank) einen Strich durch die Rechnung zu machen.

Gruss
Marcel


Achim Hilwers

unread,
Jun 14, 2003, 6:22:33 AM6/14/03
to
Hallo!

Leider bin ich erst heute dazu gekommen, wieder etwas weiter zu testen.
Meine Idee war, daß es evtl. daran liegen könnte, daß ich verschiedene
Stub-Klassen verwendete - der Client holte Sie sich aus dem Jar und der
Server nicht. Ich habe nun sowohl Server als auch Client im selben Jar -
allerdings bekomme ich wieder dieselbe Fehlermeldung - hier einmal der
Stack-Trace (Ich habe einmal die IPs geändert - Server: sss.ss.sss.sss,
Client: ccc.cc.ccc.ccc):

Lookup server [rmi://sss.ss.sss.sss:31006]
Available service : [rmi://sss.ss.sss.sss:31006/C4Server]
Exception: RemoteException occurred in server thread; nested exception is:
java.rmi.ConnectException: Connection refused to host: ccc.cc.ccc.ccc;
nested exception is:
java.net.ConnectException: Connection refused
java.rmi.ServerException: RemoteException occurred in server thread; nested
exception is:
java.rmi.ConnectException: Connection refused to host: ccc.cc.ccc.ccc;
nested exception is:
java.net.ConnectException: Connection refused
at
sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
at
sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:133)
at com.hilwers.connect4.server.CServerImpl_Stub.connect(Unknown Source)
at com.hilwers.connect4.client.CClientImpl.connect(CClientImpl.java:135)
at com.hilwers.connect4.client.C4Applet.init(C4Applet.java:182)
at
com.hilwers.connect4.gamelist.GameListApplet.startGame(GameListApplet.java:156)
at
com.hilwers.connect4.gamelist.GameListApplet$ToolbarListener.actionPerformed(GameListApplet.java:192)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1767)
at
javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1820)
at
javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:419)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:257)
at
javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:258)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:227)
at java.awt.Component.processMouseEvent(Component.java:5021)
at java.awt.Component.processEvent(Component.java:4818)
at java.awt.Container.processEvent(Container.java:1380)
at java.awt.Component.dispatchEventImpl(Component.java:3526)
at java.awt.Container.dispatchEventImpl(Container.java:1437)
at java.awt.Component.dispatchEvent(Component.java:3367)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3214)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:2929)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:2859)
at java.awt.Container.dispatchEventImpl(Container.java:1423)
at java.awt.Component.dispatchEvent(Component.java:3367)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:445)
at
java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190)
at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:98)
Caused by: java.rmi.ConnectException: Connection refused to host:
ccc.cc.ccc.ccc; nested exception is:
java.net.ConnectException: Connection refused
Caused by: java.net.ConnectException: Connection refused


Interessant finde ich dieses hier:

sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:133)
at com.hilwers.connect4.server.CServerImpl_Stub.connect(Unknown Source)

Das sieht ja bald so aus, als würde er die Stub-Klasse nicht finden. woran
könnte das liegen - mein Aufrufskript für den Server sieht folgendermaßen
aus:

java
-Djava.rmi.server.hostname=sss.ss.sss.sss
-Djava.rmi.server.codebase=http://www.domain.tld/games/connect4/connect4.jar
-Djava.security.policy=C4Server.policy -jar connect4.jar $1

Der Aufruf des Client-Applets folgendermaßen (in diesem Fall PHP-Code):

<applet code="com.hilwers.connect4.gamelist.GameListApplet.class"
codebase="games/connect4" archive="connect4.jar" width="750" height="500">
<param name="serverIp" value="sss.ss.sss.sss">
<param name="clientIp" value="ccc.cc.ccc.ccc">
<param name="port" value="31006">
<param name="userid" value="1">
</applet>

Die ClientIP ermittle ich dabi in PHP mittels $REMOTE_ADDR, und setze diese
im Client:

System.setProperty("java.rmi.server.hostname",this.getClientIp());

da der Server den Client sonst immer auf meiner lokalen IP sucht.

Kann es tatsächlich sein, daß es daran liegt, daß er die Sub-Klasse nicht
findet? Woran könnte das liegen? Sie liegt im Jar unter
/com/hilwers/connect4/server, also genau da, wo er sie auch sucht.

Gruß!

Achim

Jochen Theodorou

unread,
Jun 16, 2003, 5:32:05 AM6/16/03
to
Achim Hilwers schrieb:
> Hallo!
>
[...]
> Server: sss.ss.sss.sss,
> Client: ccc.cc.ccc.ccc):

ich kürze mal auf die relevanten Teile der Exceptions

[...]


> Exception: RemoteException occurred in server thread; nested exception is:
> java.rmi.ConnectException: Connection refused to host: ccc.cc.ccc.ccc;
> nested exception is:
> java.net.ConnectException: Connection refused
> java.rmi.ServerException: RemoteException occurred in server thread; nested
> exception is:
> java.rmi.ConnectException: Connection refused to host: ccc.cc.ccc.ccc;
> nested exception is:
> java.net.ConnectException: Connection refused

[...]


> Caused by: java.rmi.ConnectException: Connection refused to host:
> ccc.cc.ccc.ccc; nested exception is:
> java.net.ConnectException: Connection refused
> Caused by: java.net.ConnectException: Connection refused

[...]


> Das sieht ja bald so aus, als würde er die Stub-Klasse nicht finden. woran
> könnte das liegen

Nein, der Stub wird gefunden und geladen, sonst käme diese Zeile niht vor
> at com.hilwers.connect4.server.CServerImpl_Stub.connect
und die Meldung wäre auch anders.

Das Problem ist vielmehr dass dein Server sich mit dem Client verbinden
will und das nicht geht. Jetzt weiss ich aber nciht mehr, ob das an dir
liegt, oder an der Implementierung. Eigentlich müsste es ausreichen,
wenn der Client alle Verbindungen instanziert. Sobald der Server
Verbindungen aufbauen will kann es zu Problemen kommen.

[...]


> Die ClientIP ermittle ich dabi in PHP mittels $REMOTE_ADDR, und setze diese
> im Client:
>
> System.setProperty("java.rmi.server.hostname",this.getClientIp());
> da der Server den Client sonst immer auf meiner lokalen IP sucht.

Wie?
1.) Warum sucht der Server den Client? Der Server sollte niemals den
Client suchen, sondern rein passiv sein.
2.) Warum ist das sonst localhost?
3.) Was machst du bei NAT oder einem Proxy?

> Kann es tatsächlich sein, daß es daran liegt, daß er die Sub-Klasse nicht
> findet?

Nein, dann wäre es eine MarshalledException, oder wie das Ding heisst.

> Woran könnte das liegen?

Der Client weigert sich eine Verbindung zum Server aufzunehmen.

Ohne Source kann ihc da natürlich wenig machen. Stufe 1 wäre es, ein
minimales Beispiel zu erstellen und dieses zu Testen... Also ein Hallo
Welt über Applet. Wenn das nicht geht, dann kannst du das Beispiel mal
posten und wir schauen uns das an (Stufe 2). Alles weitere ergibt sich dann.

Gruss theo

Achim Hilwers

unread,
Jun 16, 2003, 1:13:27 PM6/16/03
to
Hallo!

Doch noch jemand da, der diesen Thread liest... :-) Also ich habe einmal
Deinen Rat befolgt, und ein etwas älteres Testprogramm
herausgekramt, was recht simpel ist. Ich habe es etwas umgeschrieben, damit
es im Internet läuft.

Zunächst einmal verbindet sich der Client mit dem Server:

public void connect() throws IOException, NotBoundException {
try {
if (!this.getClientIp().equals("")) {
System.out.println("Client IP is: "+this.getClientIp());
System.setProperty("java.rmi.server.hostname",this.getClientIp());
}
System.out.println("\nLookup server
[rmi://"+this.getServerIp()+":"+String.valueOf(this.getPort())+"]");
String [] l =
Naming.list("rmi://"+this.getServerIp()+":"+
String.valueOf(this.getPort()));
for(int i=0;i<l.length;i++)
System.out.println("Available service : ["+l[i]+"]");
String hs = "rmi://"+this.getServerIp()+":"+
String.valueOf(this.getPort())+"/"+RemoteDate.LOOKUPNAME;
netConn = (RemoteDate)Naming.lookup(hs);
System.out.println(this.getDate());
netConn.connect(this);
} catch (Exception e) {
System.err.println("RemoteDate-Exception: " +
e.getMessage());
e.printStackTrace();
}
}

(Ich hoffe der Code ist lesbar - ich habe versucht, in der Newsgroup unter
80 Zeichen zu bleiben)

Srver-IP, Port und ClientIP werden von außen gesetzt. Eine Erklärung, warum
auch die ClientIP, folgt weiter unten. :-)

Auf Server-Seite sieht das dann so aus:

public void connect(IfClient d) throws RemoteException {
System.out.println("Client verbindet: " + d);
list.add(d);
}

Er gibt also lediglich die Client-Daten aus und fügt den Client zur Liste
der verbundenen Clients hinzu.

Die Ausgabe sieht so aus:

Client verbindet: Client_Stub[RemoteStub [ref:
[endpoint:[192.168.0.20:34746](remote),objID:[a17083:f5d175d084:-8000,
0]]]]

Das dauert ganze drei Minuten. Hier kann man auch schön sehen, was ich
meinte, daß der Server den client auf meiner lokalen IP sucht. Die
192.168.0.20 ist die lokale IP des Rechners, mit dem ich hier verbinde.
Ich befinde mich hinter einem Router mit Firewall. Der Router führt
Masquerading durch und die Firewall läßt nun testweise alles durch, was
kommt. Ich bekomme auch keinerlei Meldungen, daß sie irgend etwas
abblocken würde.

Der Client holt dich beim Verbinden die Server-Zeit ab, was wunderbar
funktioniert - hier der Code:

public String getDate() {
String hs = "";
try {
Date today = netConn.getRemoteDate();
hs =today.toString();
} catch (Exception e) {
System.err.println("RemoteDate-Exception: " + e.getMessage());
e.printStackTrace();
}
return hs;
}

Auf Server-Seite sieht das Ganze so aus:

public Date getRemoteDate() throws RemoteException {
return new Date();
}

Wie gesagt - das klappt wunderbar.

Nun kommt aber folgendes, was ich eben auch ähnlich in meinem Spiel
erreichen will - der Client soll nun eine Nachricht schicken, die der
Server wiederum an alle Clients weitergibt:

public void sendMessage(String message) {
try {
netConn.sendMessage(message);
} catch (Exception e) {
System.err.println("RemoteDate-Exception: " + e.getMessage());
e.printStackTrace();
}
}

Auf dem Server ist die Sache folgendermaßen implementiert:

public void sendMessage(String message) throws RemoteException {
System.out.println(message);
Iterator it = list.iterator();
while (it.hasNext()){
try {
((IfClient)it.next()).alert(message);
} catch (RemoteException re) {
System.out.println("Exception alerting client, removing it.");
System.out.println(re);
re.printStackTrace();
it.remove();
} //try
} //while hasnext
}

Er geht also die Liste der Clients durch und ruft die Callback-Methode
"alert" jedes Clients auf, den er finden kann.

Dies ist die Methode alert:

public void alert(String message) throws RemoteException {
System.out.println(message);
}

Ich schicke vom Client aus den String "Hallo" an den Server. Dieser gibt den
Text auch schön brav aus, kann ihn dann aber nicht an die anderen Clients
(in diesem Fall ist es ja nur einer) weiterreichen, da dort wiederum nichts
ankommt.

Server-Seitig bekomme ich dann folgenden Stack-Trace:

Exception alerting client, removing it.
java.rmi.ConnectException: Connection refused to host: 192.168.0.20;
nested exception is:
java.net.ConnectException: Connection timed out
java.rmi.ConnectException: Connection refused to host: 192.168.0.20;
nested exception is:
java.net.ConnectException: Connection timed out
java.net.ConnectException: Connection timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:355)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:142)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:129)
at java.net.Socket.<init>(Socket.java:273)
at java.net.Socket.<init>(Socket.java:100)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket
(RMIDirectSocketFactory.java:25)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket
(RMIMasterSocketFactory.java:120)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:499)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:190)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:174)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:83)
at Client_Stub.alert(Unknown Source)
at RemoteDateImpl.sendMessage(RemoteDateImpl.java:43)
at java.lang.reflect.Method.invoke(Native Method)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241)
at sun.rmi.transport.Transport$1.run(Transport.java:152)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:148)
at
sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:465)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run
(TCPTransport.java:706)
at java.lang.Thread.run(Thread.java:484)

Was in diesem Fall ja logisch ist - wie soll mein Internetserver auch wohl
meinen Client unter der adresse 192.168.0.20 erreichen können? :-)
Ich weiß nun nicht, warum das
System.setProperty("java.rmi.server.hostname",this.getClientIp());
in diesem Beispiel nicht funktioniert. Bei meinem anderen Programm tut es
das - der Server registriert dann die Connection von der korrekten IP, die
mein Rechner im Internet hat. Das muß ich noch einmal ausprobieren.

(Der Thread, der hier im Stacktrace auftaucht, kommt noch von meinen
Experimenten und tut momentan nichts weltbewegendes, außer "Tick" zu sagen.
:-) In meinem richtigen Server läuft alerdings auch ein Thread.)

Interessant ist aber schon einmal der restliche Code, da er in meinem
anderen Programm im Grunde nicht anders ist.

Hier zusätzlich noch die Code-Teile, mit denen ich den Server starte:

Testprogramm:

public static void main(String[] args) {
//Wir benötigen einen SecurityManager für den Download der Klassen:
System.setSecurityManager(new RMISecurityManager());

try {
//Erzeuge eine Instanz der server-Obejtkes:
RemoteDateImpl im = new RemoteDateImpl();
System.out.println("DateServer startet...");
//Lokalisiere es in der RMI-Registry
System.out.println("DateServer registriert mit RMI...");
Naming.rebind(RemoteDate.LOOKUPNAME, im);
im.start();
System.out.println("DateServer bereit.");
} catch (Exception e) {
System.err.println(e);
System.exit(1);
} //try..catch
} //main


In meinem Spiel sieht es etwas anders aus, da das nachher auf einem anderen
Port laufen muß und auch gleich die rmiregstry startet:

try {
//Erzeuge eine Instanz der server-Obejtkes:
CServerImpl im = new CServerImpl();
System.out.println("Server starting...");
//Lokalisiere es in der RMI-Registry

if (!codeBase.equals("")) {
System.setProperty("java.rmi.server.codebase",codeBase);
}
System.out.println("Using
codebase"+System.getProperty("java.rmi.server.codebase"));

System.out.println("Server registering with RMI...");
Registry reg = LocateRegistry.createRegistry(port);
reg.rebind(CServer.LOOKUPNAME, im);
System.out.println("Server listening on port "+port+".");

System.out.println("Server ready and waiting for connections.");
} catch (Exception e) {
System.err.println(e);
System.exit(1);
} //try..catch


So, ich hoffe, anhand der Code-Framente, kann man sehen, ob ich irgend etwas
vom Programm her falsch mache. Ich bin langsam mit meinem Latein am Ende.

Gruß!

Achim

Achim Hilwers

unread,
Jun 16, 2003, 5:24:24 PM6/16/03
to
Hallo!

Ich bin's noch einmal. :-)

Ich wollte nun sichergehen, ob es evtl. daran liegt, daß ich über einen
Router ins Netz gehe.

Also habe ich mir einen kleinen Text-Client gebastelt (nach gleichem
Strickmuster wie das bereits vorhandene Applet), Java auf dem Router
installiert, die Firewall ausgeschaltet und diesen Client direkt auf dem
Router gestartet.

Das Ergebnis war, daß es sich exakt so verhalten hat, wie bereits
beschrieben. Also kann ich eigentlich den Router/die Firewall als mögliche
Fehlerquelle ausschließen.

Gruß!

Achim

Jochen Theodorou

unread,
Jun 17, 2003, 4:44:57 AM6/17/03
to
Achim Hilwers schrieb:

> Hallo!
>
> Doch noch jemand da, der diesen Thread liest... :-)

ja, ich hba etwas Pause gemacht ;-)

> Also ich habe einmal Deinen Rat befolgt, und ein etwas älteres
> Testprogramm herausgekramt, was recht simpel ist.

gut.

> Ich habe es etwas umgeschrieben, damit es im Internet läuft.
>
> Zunächst einmal verbindet sich der Client mit dem Server:

[...]


> Srver-IP, Port und ClientIP werden von außen gesetzt. Eine Erklärung,
> warum auch die ClientIP, folgt weiter unten. :-)
>
> Auf Server-Seite sieht das dann so aus:
>
> public void connect(IfClient d) throws RemoteException {
> System.out.println("Client verbindet: " + d); list.add(d); }

genau hier (eigentlich schon in der connect-Methode des Client) liegt
das Problem. Ganz gleich ob deine Firewall jetzt NAT einsetzt, oder
nicht, wie soll der Server sich denn zu einem Client verbiinden, der
hinter einem Router liegt? Wenn der Client nur eine private IP besitzt
(zb. 192.168.x.x, oder 10.x.x.x) kann der Server sich ja schlecht mit
dem Client verbinden. Und das muss er.. Wenn du ein Clientobjekt zum
Server schickst, dann baut der Server eine Verbindung zum Client auf.
Instanziert wird das ganze vom Server, der allerdings als einzige
Information die private IP des Client hat und demnach nicht mal über den
ersten Router im Internet kommt, weil dieser die privaten IPs
normalerweise nicht durchroutet.

Es fallen mir folgende Möglichkeiten ein:

1.) Du änderst dein System, dass die Clients nicht sich selbst am Server
hinterlegen, sondern die Clients fragen regelmässig ab, ob der Server
was neues hat... das ist natürlich mit mehr Traffic verbunden.

2.) Du spielst in RMI rum, damit der Client, wenn er sich als Objekt dem
Server hinzufügt, selbst die Verbindung öffnet.... Das ist natürlich mit
erheblichen Aufwand bzw. Einarbeitung verbunden... Vielleicht sollte ich
mein altes RMI-Projekt mal wieder aus der sChublade kramen und meine
alternative Implementierung wieder etwas vorantreiben... nur hilft dir
das natürlich jetzt wenig.

3.) du machst eine kombinierte Lösung mit RMI für die komplizierten
Sachen und einem weiteren Socket, als Eventline. Also, der CLient macht
zusätzlich eine Socketverbindung mit dem Server auf und wenn der Server
eine Nachricht für den CLient hat, dann schickt der über diese
Verbindung ein byte... ein einzelnes reicht, weil der Client nur wissen
muss, dass da etwas gekommen ist. Was es genau ist, kann er dann über
RMI fragen. Das dürfte den Verkehr minimal halten.

> Er gibt also lediglich die Client-Daten aus und fügt den Client zur
> Liste der verbundenen Clients hinzu.
>
> Die Ausgabe sieht so aus:
>
> Client verbindet: Client_Stub[RemoteStub [ref:
> [endpoint:[192.168.0.20:34746](remote),objID:[a17083:f5d175d084:-8000,
> 0]]]]

und hier sieht man eine private IP

> Das dauert ganze drei Minuten.

klar. Aus RMISocketFactory:
> The default socket factory implementation used goes through a
> three-tiered approach to creating client sockets. First, a direct
> socket connection to the remote VM is attempted. If that fails (due
> to a firewall), the runtime uses HTTP with the explicit port number
> of the server. If the firewall does not allow this type of
> communication, then HTTP to a cgi-bin script on the server is used to
> POST the RMI call.

man kann den Timeout auch irgendwo setzen

> Hier kann man auch schön sehen, was ich
> meinte, daß der Server den client auf meiner lokalen IP sucht. Die
> 192.168.0.20 ist die lokale IP des Rechners, mit dem ich hier
> verbinde. Ich befinde mich hinter einem Router mit Firewall. Der
> Router führt Masquerading durch und die Firewall läßt nun testweise
> alles durch, was kommt. Ich bekomme auch keinerlei Meldungen, daß
> sie irgend etwas abblocken würde.

weil eine weitere Verbindung vom Server aus aufgemacht wird, und der
kommt erst garnicht bis zu deiner Firewall... Nochmal... das liegt
drana, dass du ein Remotobjekt des Client zum Server schickst.

> Der Client holt dich beim Verbinden die Server-Zeit ab, was wunderbar

> funktioniert [...]

klar, denn dafür muss der Server sich nicht mit dem Client verbinden.

[...]


> Was in diesem Fall ja logisch ist - wie soll mein Internetserver auch
> wohl meinen Client unter der adresse 192.168.0.20 erreichen können?
> :-) Ich weiß nun nicht, warum das
> System.setProperty("java.rmi.server.hostname",this.getClientIp()); in
> diesem Beispiel nicht funktioniert. Bei meinem anderen Programm tut
> es das - der Server registriert dann die Connection von der korrekten
> IP, die mein Rechner im Internet hat. Das muß ich noch einmal
> ausprobieren.

dein Client ist hinter einer Firewall und hat selbst keine Internetip.
Wie soll es da also für den Client eine korrekte IP geben?

[...]


> So, ich hoffe, anhand der Code-Framente, kann man sehen, ob ich
> irgend etwas vom Programm her falsch mache. Ich bin langsam mit
> meinem Latein am Ende.

nicht direkt, du hast eben nur die Grundregel vergessen, dass im
Internet die Verbindung meist vom Client initiert wird, weil der Client
meist nicht direkt erreichbr ist.

zu deinem anderen Posting noch:

Nein, den welche IP hat denn deine Firewall an den Server geschickt? Der
Router wird ja mindestens 2 Netzwerkips haben.
InetAdress.getAllByName(host) hilft da weiter

Gruss theo

Achim Hilwers

unread,
Jun 17, 2003, 8:51:55 AM6/17/03
to
Hallo!

> 1.) Du änderst dein System, dass die Clients nicht sich selbst am Server
> hinterlegen, sondern die Clients fragen regelmässig ab, ob der Server
> was neues hat... das ist natürlich mit mehr Traffic verbunden.

Das wäre in meinem Fall auch irgendwie suboptimal. :-)

> 3.) du machst eine kombinierte Lösung mit RMI für die komplizierten
> Sachen und einem weiteren Socket, als Eventline. Also, der CLient macht
> zusätzlich eine Socketverbindung mit dem Server auf und wenn der Server
> eine Nachricht für den CLient hat, dann schickt der über diese
> Verbindung ein byte... ein einzelnes reicht, weil der Client nur wissen
> muss, dass da etwas gekommen ist. Was es genau ist, kann er dann über
> RMI fragen. Das dürfte den Verkehr minimal halten.

Habe ich denn eine Chance, daß es mit der einfachen Socket-Verbindung besser
klappt als mit RMI? Ansonsten finde ich diese Möglichkeit schon sehr
interessant, zumal die Änderungen auch verhältnismäßig moderat ausfallen
würden.

> Nein, den welche IP hat denn deine Firewall an den Server geschickt? Der
> Router wird ja mindestens 2 Netzwerkips haben.
> InetAdress.getAllByName(host) hilft da weiter

Die Firewall war ja ausgeschaltet. Ich habe den Client also direkt auf dem
Rechner ausgeführt, der per ISDN am Internet hängt. Aus diesem Grund war
ich davon ausgegangen, die Firewall als Fehlerquelle ausschließen zu
können.

Gruß!

Achim

Jochen Theodorou

unread,
Jun 17, 2003, 1:24:24 PM6/17/03
to
Achim Hilwers schrieb:
> Hallo!
>
[...]
>>3.) du machst eine kombinierte Lösung mit RMI für die komplizierten
>>Sachen und einem weiteren Socket, als Eventline. Also, der CLient macht
>>zusätzlich eine Socketverbindung mit dem Server auf und wenn der Server
>>eine Nachricht für den CLient hat, dann schickt der über diese
>>Verbindung ein byte... ein einzelnes reicht, weil der Client nur wissen
>>muss, dass da etwas gekommen ist. Was es genau ist, kann er dann über
>>RMI fragen. Das dürfte den Verkehr minimal halten.
>
> Habe ich denn eine Chance, daß es mit der einfachen Socket-Verbindung besser
> klappt als mit RMI?

Nochmal..
Stufe 1:
Du holhst dir ein Serverobvjekt vom Server, was darin resultiert, dass
der Client eine Vebindung zum Server aufmacht. Dies scheint ja zu
funktionieren (Meldung vom Client beim Server ausgeben geht ja).
Stufe 2:
Was du dann bisher machst ist, dem Server ein Objekt zu geben, was den
Client representiert. Das resultiert darin, dass der Server eine
Verbindung zum Client aufmachen will und das geht schief.

Wenn der Client jetzt eine Socketverbindung zum Server aufmacht, dann
hast du ja was ähnliches wie Stufe 1 und das ging ja. Mein Vorschlag für
das Protocoll:

Client hohlt dich ein Serverobjekt. Er ruft beim auf dem Serverobjekt
eine Methode auf, die dem Client eine ID zurückgeben soll. Dann macht
der Client eine Socketverbindung zum Server auf und schickt diese ID an
den Server. Der Server weiss dann, dass dieser Socket zu jenem Client
gehört und kann ihn diesem zuordnen. Wenn du die Clients nicht
identifizieren musst, dann ist es noch einfacher. Also ich sehe gute
Chancen, da es keine Verbindung gibt, die vom Server aufgebaut werden soll.

> Ansonsten finde ich diese Möglichkeit schon sehr
> interessant, zumal die Änderungen auch verhältnismäßig moderat ausfallen
> würden.

ja, denke ich auch.

>>Nein, den welche IP hat denn deine Firewall an den Server geschickt? Der
>>Router wird ja mindestens 2 Netzwerkips haben.
>>InetAdress.getAllByName(host) hilft da weiter
>
> Die Firewall war ja ausgeschaltet. Ich habe den Client also direkt auf dem
> Rechner ausgeführt, der per ISDN am Internet hängt. Aus diesem Grund war
> ich davon ausgegangen, die Firewall als Fehlerquelle ausschließen zu
> können.

Ok, dann könnte natürlich noch ein Proxy schuld sein... Trotzdem wäre
die IP interessant gewesen. Jedenfalls ist Lösungsvorschlag 3 da besser
geeignet.. theoretisch könnte man da noch mit http ran, damit auch die
Leute, die nur über Proxys ins Netz dürfen noch was anfangen können,
aber ich glaube das lassen wir erstmal ;-)

Gruss theo

Achim Hilwers

unread,
Jun 18, 2003, 7:00:23 AM6/18/03
to
Hallo!

So, ich habe mir jetzt eine kleine EventLine gebastelt und kann nun per
Socket Nachrichten zum Client schicken. Nun werde ich mich mal daran
machen, Server und Client entsprechend umzuschreiben.

Danke für Deinen Tip mit den Sockets! Dadurch hatte ich seit Ewigkeiten mal
wieder das erste Erfolgserlebnis. :-)

Bis zum nächsten Problem! ;-)

Achim

0 new messages