RMI Problem: ConnectionException

Hallo!

Bei meinem RMI Programm bekomme ich clientseitig immer eine ConnectionException, die ich mir par tout nicht erklären kann.

Eclipse sagt:

java.rmi.ConnectException: Connection refused to host: 127.0.1.1; 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 client.Client.main(Client.java:28)
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:384)
at java.net.Socket.connect(Socket.java:546)
at java.net.Socket.connect(Socket.java:495)
at java.net.Socket.(Socket.java:392)
at java.net.Socket.(Socket.java:206)
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)
… 5 more

Das alles wirft der Client. Das exportieren des Ojects, erstellen der Registry und das stubs bei Server geht gut. In einem anderen Programm läuft derselbe Code ab, und alles geht glatt. Der einzige Unterschied ist, dass ich in diesem Programm ein generisches Interface verwende, wobei die Klassen es aber konkretisiert implementieren.


import interfaces.JobHandlerInterface;

import interfaces.JobInterface;

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

import server.Job;
import server.Server;
import tasks.*;

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

//		System.setSecurityManager(new SecurityManager());
		try {
			
			Registry registry = LocateRegistry.getRegistry(Server.REGISTRY_PORT);
			
			JobInterface jobservice = (JobInterface) registry.lookup(Server.JOBSERVICE_NAME);
			
			JobHandlerInterface handlerstub = jobservice.executeJob(new Job(new Add(5, 6), new Rand(), new Sub(7, 7)));
			
			System.out.println(handlerstub.getResults());
			
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (NotBoundException e) {
			e.printStackTrace();
		}
	}
}

jobservice ist mein exportiertes Objekt. Add(), Rand() und Sub() implementieren das generische Interface mit konkreten Typen (Integer, Double). handlerstub wird in jobservice.executeJob() erzeugt und exportiert.

Aber ich kann nirgendwo ein Problem feststellen :frowning: Bei der Fehlermeldung oben bereitet mir vor allem die Zeile

at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)

Kopfschmerzen. Was könnte die bedeuten?

EDIT: Wäre mir mit einem SecurityManager geholfen?

Hm… meine Erfahrung mit RMI ist zwar sehr beschränkt (und vielleicht erkennst du das auch an meiner Antwort). Und inwieweit die Aussage
„In einem anderen Programm läuft derselbe Code ab, und alles geht glatt.“
zutreffen kann … also, irgendwo muss ja irgendein Unterschied sein :wink:
Aber Stichpunkte aus meiner (wenigen) Erfahrung heraus:

  • Dieses rmiregistry Dingens muss gestartet sein
  • Man muss aufpassen, dass die Windows-Firewall nicht irgendwas blockt
  • localhost ist 127.0.0.1 …
    Sorry falls das irrelevante Trivialitäten sind :o

RMI ist ziemlich sensibel. Wenn man nur eines von mehreren wichtigen Dingen vergisst oder verkehrt macht, funktioniert das Ganze nicht und zieht eine oftmals schwierige Fehlersuche nach sich.

Bist du sicher, dass die RMIRegistry gestartet wurde und du einen Server laufen hast, der ein Remote-Objekt an der Registry angemeldet hat?

Ein SecurityManager hilft dir hier noch nicht, die Fehlermeldung würde anders lauten.

Ja, der Server läuft. Sein Code:


import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Random;

import interfaces.JobInterface;

public class Server {

	public static final int REGISTRY_PORT = new Random().nextInt(10000) + 40000; 
	public static final String JOBSERVICE_NAME = "Jobservice";
	
	public static void main(String[] args) {
	
		try {
			JobInterface jobservice =  new JobService();
			
			JobInterface stub = (JobInterface) UnicastRemoteObject.exportObject(jobservice, 0);
			
			Registry registry = LocateRegistry.createRegistry(REGISTRY_PORT);
			
			registry.rebind(JOBSERVICE_NAME, stub);
			
			System.out.println("Exported");
			
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
}

Da das Programm nur auf einem Rechner läuft (Ubuntu) müsste 127.0.0.1 doch nicht das Problem sein.

Wenn ich im Client einen SecurityManager „istalliere“ ändern sich interessanterweise die Exceptions in eine AccessControlException:


Exception in thread „main“ java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:49983 connect,resolve)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:342)
at java.security.AccessController.checkPermission(AccessController.java:553)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkConnect(SecurityManager.java:1051)
at java.net.Socket.connect(Socket.java:541)
at java.net.Socket.connect(Socket.java:495)
at java.net.Socket.(Socket.java:392)
at java.net.Socket.(Socket.java:206)
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)
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 client.Client.main(Client.java:28)

Weiß jemand, was das bedeutet? Wie ihr seht, bin ich auf dem Gebiet noch ein ziemlicher Noob :frowning:

Ok, hab den Fehler gefunden. Es lag an der Zeile:
public static final int REGISTRY_PORT = new Random().nextInt(10000) + 40000;

Ich habe es mit 50000 ersetzt. Aber wieso da kein Random() sein darf, versteh ich nicht. REGISTRY_PORT steht doch zur Laufzeit fest… und es sogar noch final :-S

Der Client muss den Port doch auch kennen.
Wenn du den Port zufällig festlegst, weiß der Client nicht, welchen Port der Server für ihn geöffnet hat.

Mit
public static final int REGISTRY_PORT = new Random(12345).nextInt(10000) + 40000;
(oder einer anderen Konstante dort) würde es wohl sogar funktionieren :wink:

Ja. Rein zufällig natürlich… :smiley:

Nein, mit Random(12345) gehts auch nur ein Mal, denn da kommt immer dieselbe Zahl raus (=Port).

Mir ist schon bewusst, dass der Client den Port kennen muss… Aber die Variable REGISTRY_PORT steht doch schon fest, bevor der Client überhaupt gestartet wird. Oder hab ich da einen Denkfehler? :-S

Die RMIRegistry arbeitet an einem Standardport 1099, das stimmt.
Man kann aber auch einen anderen Port definieren.
Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT); //Standardport binden

Registry registry = LocateRegistry.createRegistry(1100); //benutzerdefinierten Port binden