# RMI auf lokalem Rechner



## mamelinchen (28. Jun 2010)

Ich habe einen RMIThread, der mir in der run() Methode die Methoden eines RMIServers aufruft.Dabei wird ein Stack zurückgegeben und in ergebnis gespeichert.

Ich habe 2 RMI-Server, sowie 2 dazugehörige Interfaces.

//5002:mein gewählter Port für Server
Wenn im Browser der localhost mit dem serverport5002 aufgerufen wird, wird der zentrale Server aufgerufen, der 
eine HTML Seite an den Browser schickt. DAs funktioniert auch alles. Der User gibt 2 Einträge in eine Form ein, diese werden zum Server gebracht, anschliessen dem RMIThread übergeben und dann zu den beiden RMIServen geschickt.

Das ist die RMIServerklassen mit der main(beide sind identisch und der Rest sind nur Methoden):

Das RMIIterface implementiert Remote


```
public class RMIServer extends UnicastRemoteObject implements RMIInterface {
	// Konstruktor
	public RMIServer() throws RemoteException {
		super();
	}
	public static void main(String[] args) {
		try {
			if (System.getSecurityManager() == null) {
				System.setSecurityManager(new RMISecurityManager());
			}
			RMIServer rmi = new RMIServer();
			/*
			 * die statische Methode rebind(String name, Remote obj) der Klasse
			 * Naming meldet den Dienst bei der Registry an String name ist die
			 * gueltige URL fuer das Server-Objekt. kann auch aussehen:
			 * Naming.bind(rmi://sun36/MyService",ds)
			 */
			LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
			Naming.rebind("rmi://localhost:6601/RMIServer", rmi);
			System.out.println("Telefonserver 2");
			System.out.println("Serverbind");
			System.out.println("Der Server wartet auf Anfragen...");
		} catch (Exception e) {
			System.out.println("Fehler im RMI-Server");
			e.printStackTrace();
		}
	}
```

//list ist mein Stack mit den Werten aus der Form.
Das ganze soll eine 3-Tier Architektur darstellen.


```
//RMIThread, startet Verbindung zum RMIServer

public void run() {
		try {
	Registry registry = LocateRegistry.getRegistry();
			// Connect to remote server and service
			if (server.equals("localhost")) {

				RMIInterface remoteSearch = (RMIInterface) Naming.lookup("rmi://"+ server + ":" + port + "/" + name);
				if (list.size() == 2) {
					if (list.get(0).matches("{1}[0-9]*")
							&& list.get(1).matches("[a-zA-Z]*")) {
						ergebnis = remoteSearch.suchNummer(list.get(0) + "_"
								+ list.get(1));
					} else
						ergebnis = remoteSearch.suchNummer(list.get(1) + "_"
								+ list.get(0));
				} else if (list.get(0).matches("{1}[0-9]*")) {
					ergebnis = remoteSearch.suchNummer(list.get(0));
				} else
					ergebnis = remoteSearch.suchName(list.get(0));
			} else {
				RMIInterface2 remoteSearch = (RMIInterface2) Naming.lookup("//"
						+ server + ":" + port + "/" + name);
				if (list.size() == 2) {
					if (list.get(0).matches("{1}[0-9]*")
							&& list.get(1).matches("[a-zA-Z]*")) {
						ergebnis = remoteSearch.suchNummer(list.get(0) + "_"
								+ list.get(1));
					} else
						ergebnis = remoteSearch.suchNummer(list.get(1) + "_"
								+ list.get(0));
				} else if (list.get(0).matches("{1}[0-9]*")) {
					ergebnis = remoteSearch.suchNummer(list.get(0));
				} else
					ergebnis = remoteSearch.suchName(list.get(0));
			}
		}
```


Wenn ich nun den TelefonServer mittels des Browsers starte,kommt folgende Meldung:

```
java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: 
	java.net.ConnectException: Connection refused
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
	at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
	at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
	at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:340)
	at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
	at java.rmi.Naming.lookup(Naming.java:101)
	at telefonserver.MyClientThread.run(MyClientThread.java:38)
Caused by: java.net.ConnectException: Connection refused
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:310)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:176)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:163)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:381)
	at java.net.Socket.connect(Socket.java:537)
	at java.net.Socket.connect(Socket.java:487)
	at java.net.Socket.<init>(Socket.java:384)
	at java.net.Socket.<init>(Socket.java:198)
	at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
	at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:146)
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
	... 6 more
java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: 
	java.net.ConnectException: Connection refused
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
	at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
	at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
	at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:340)
	at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
	at java.rmi.Naming.lookup(Naming.java:101)
	at telefonserver.MyClientThread.run(MyClientThread.java:38)
Caused by: java.net.ConnectException: Connection refused
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:310)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:176)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:163)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:381)
	at java.net.Socket.connect(Socket.java:537)
	at java.net.Socket.connect(Socket.java:487)
	at java.net.Socket.<init>(Socket.java:384)
	at java.net.Socket.<init>(Socket.java:198)
	at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
	at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:146)
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
	... 6 more
Exception in thread "main" java.lang.NullPointerException
	at telefonserver.Telefon.ausgabeNamenStack(Telefon.java:130)
	at telefonserver.Telefon.main(Telefon.java:98)
```


Ich will das ganze erstmal auf einen Server laufen lassen, deshalb localhost.
Gelookupt wird nach rmi://localhost:6601/RMIServer
und rmi://localhost:6601/RMIServerZwei
Klingt doch logisch!
Oder ist der Pfad falsch?
Die RMIs liegen in einem anderen package als der Server, hat es damit was zu tun?
Ich weiss echt nicht wo der Fehler ist,kann Nachts schon net mehr schlafen...


----------



## Marco13 (28. Jun 2010)

Kleiner, hilfloser Hinweis von jemandem, der eigentlich GARkeine Ahnung von Netzwerkzeux hat: Wenn die Windows-Firewall aktiv ist, kann es afaik zu dieem Fehler kommen - aber vielleicht hat noch jemand eine ... fundierter-qualifiziertere, spezifischere Antwort ...


----------



## fastjack (28. Jun 2010)

Manchmal gibt es Probleme mit der localhost Auflösung, schon mal 127.0.0.1 probiert ?


----------



## mamelinchen (1. Jul 2010)

Okay, aber wie wird denn der RMIServer gestartet?

Ich rufe ja nur den Telefonserver auf, wir dann der RMIServer selber gestartet?Automatisch wenn er aufgerufen wird?WENN IHN JEMAND ANFRAGT?

Ich soll ja einen auf einem Rechner laufen lassen , den zweiten aufn Zweiten und den Telefonserver auf einem dritten Host, sowei auf einem vierten per Browser mit dem Telefonserver zu kommunizieren.

Wie sage ich  denn der Registry, das er den Dienst auf den Port 6602 anmelden solll, in der Kommandoziele geht es so oder:

rmci RMIServer
rmiregistry 6602

Wie und wo sage ich das jetzt in Java?

So wie ich das gemacht hab bekommt er doch einen so zugewiesen.

Ich mach das zum ersten MAL und ich habe keine AHNUNG!


----------



## L-ectron-X (1. Jul 2010)

mamelinchen hat gesagt.:


> Wie sage ich  denn der Registry, das er den Dienst auf den Port 6602 anmelden solll,


Ich weiß nicht, ob man die Registry auffordern kann, einen Dienst unabhängig von der RMIRegistry an einen anderen/weiteren Port zu binden. Aber die Registry kann man an einen Port binden, an dem dann die mehrere Remote-Objekte angemeldet und von den Clients abgerufen werden können. Per Java-Code geht das im Server so:

```
private Registry registry;
[...]

LocateRegistry.createRegistry(6602); //Port binden
registry = LocateRegistry.getRegistry();
```
LocateRegistry#createRegistry(int port)

Nebeneffekt: Du brauchst die RMIRegistry nicht mehr von Hand starten, das macht dann der Server gleich mit.
Die Ports werden aber nicht automatisch geöffnet, das muss dann noch in der Firewall/Router erledigt werden.


----------



## mamelinchen (1. Jul 2010)

Ich lasse es ja auf einem Windows und einem Linux laufen, 
das mit der Registry hab ich jetzt nun kriege ICH den Fehler , wenn ich den RMIServer starte auf dem Linux und dem Windows:


```
java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:6601 connect,resolve)
	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkConnect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at java.net.Socket.<init>(Unknown Source)
	at java.net.Socket.<init>(Unknown Source)
	at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(Unknown Source)
```

DAS KANN DOCH NICHT SO SCHWER SEIN!


----------



## L-ectron-X (1. Jul 2010)

Kann sein, dass dein Server noch mehr Rechte benötigt.
Dazu legst du mal mit einem Texteditor eine Policy-Datei an, die du ins Verzeichnis der Jar-Datei deines Servers legst:


			
				rmi.policy hat gesagt.:
			
		

> grant {
> permission java.security.AllPermission;
> };



Beim Start musst du diese dann mit angeben:


			
				RMIServerStarter.bat hat gesagt.:
			
		

> start java -Djava.security.policy=rmi.policy -Djava.rmi.server.codebase=http://deine-domain-oder-ip-adresse/ -jar RMIServer.jar


----------



## mamelinchen (1. Jul 2010)

Genau das habe ich ausgeführt unter Windows, immernoch der gleiche Fehler......


----------



## L-ectron-X (1. Jul 2010)

Hmmm. RMI ist kompliziert und hinterhältig. Das kann alles mögliche sein.
Wenn du eine Sache vergisst, oder verkehrt machst, hast du richtig Arbeit damit.
Kannst du mal deinen kompletten Code hochladen (zip etc.), dass man das mal ausprobieren kann?


----------



## mamelinchen (1. Jul 2010)

Kann ich dich unter Skype adden?


----------



## tuxedo (2. Jul 2010)

L-ectron-X hat gesagt.:


> Hmmm. RMI ist kompliziert und hinterhältig. Das kann alles mögliche sein.
> Wenn du eine Sache vergisst, oder verkehrt machst, hast du richtig Arbeit damit.



Kann ich voll und ganz bestätigen 

Aber es gibt ja Alternativen :toll:



> rmci RMIServer



???:L Ist das der RMI Stub-Compiler? Den braucht man seit Java 5 nicht mehr. Java regelt das auztomatisch intern... Vielleicht gibt's deshalb Probleme.


----------



## fastjack (2. Jul 2010)

Nur falls es noch nicht erwähnt wurde: Blockiert vielleicht eine Firewall den Port? Oder wird der Port schon von einer anderen Software verwendet?


----------



## L-ectron-X (2. Jul 2010)

Ich habe gestern abend noch den Quellcode bekommen.
Es wird eine AccessControlException beim Starten des RMI-Servers geworfen. Die auslösende Codezeile scheint die zu sein, bei der der Server die Remote-Objekte an die RMI-Registry bindet (Naming#rebind(...)).


----------

