views:

1061

answers:

2

Hi there!

Because I didn't want to implement a communication protocol for my client-server based application, I implemented a RMI client and a RMI server on both sides for the information exchange between the two components.

If I try to use my application by starting the two components on the same machine, everything is working fine. But if I split the components to two different computers (Kubuntu 9.04 within as a virtual machine within an Windows 7 RC environment with disabled firewall and a native Ubuntu 9.04 environment), it seems like the RMI client is not able to execute the methods which are defined on the server side. (Every functions call leads to a RMI exception.)

Currently I only set the system property "java.rmi.server.hostname" on both sides to the network interface which should be used for the data exchange and registered the default port for the communication with rmi daemon (?) rmid.

Does somebody has an idea what might be going wrong? Do I have to set some other parameters like "java.rmi.server.codebase" (http://java.sun.com/j2se/1.4.2/docs/guide/rmi/javarmiproperties.html) to be able to use the RMI functionality within my application?

Edit: Okay, here is some additional information for you:

In the initialization phase my client tries to establish a connection to the RMI server of server component, which was initialized using the following two methods:

private void initialize()
{
 // set ip address of rmi server
 System.setProperty("java.rmi.server.hostname", ipAddress);

 // try to register rmi server
 try
 {
  LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
 }
 catch (Exception e)
 {
  // ignore
 }
}

public void start()
{
 System.out.print("starting master control RMI server ...");

 try
 {
  Naming.rebind("MasterControl", this);
 }
 catch (Exception e)
 {
  System.out.println("error: could not initialize master control RMI server");
  System.exit(1);
 }

 // set running flag
 isRunning = true;

 System.out.println(" done");
}

"ipAddress" is here the ip address of the network interface of the server component.

The method which is used by the client component to establish the connection looks like this:

    public void connect()
{
 // build connection url
 String url = "rmi://" + masterControlIpAddress + "/MasterControl";

 System.out.println(url);

 System.out.print("connecting to master control ...");

 // try to connect to master control server
 while (connection == null)
 {
  try
  {
   connection = (MasterControlInterface) Naming.lookup(url);
   id = connection.register(localIpAddress);
  }
  catch (Exception e)
  {
   // ignore
  }

  if (connection == null)
  {
   try
   {
    Thread.sleep(100);
   }
   catch (InterruptedException e)
   {
    e.printStackTrace();
   }
  }
 }

 System.out.println(" done");
}

As you can see my client calls a function to register the connection at the server:

@Override
public int register(String ipAddress) throws RemoteException
{
 // add connection to registrationHandler
 masterControl.registrationHandler.addConnection(ipAddress);

 // log
 int connectionCount = masterControl.registrationHandler.getConnectionCount();
 System.out.println("slave control (" + ipAddress + ") instance has been registered at the master control server under the following id: " + connectionCount);

 return connectionCount;
}

If I run my program using a real network connection, the text "slave control ..." is not displayed on the server side. Therefore I'm not sure, if the function is really called by the client component.

After the client component is intialized it tries to notify the server component by calling the following method using it's RMI connection to the server:

public void sendInitializationDone()
{
 try
 {
  connection.initializationDone();
 }
 catch (RemoteException e)
 {
  System.out.println("error: could not send 'initializationDone' message to master control");
  System.out.println(e);
  System.exit(1);
 }
}

to set a flag on the server side.

The error occures inside this function on the client side:

java.rmi.ConnectException: Connection refused to host 127.0.1.1; nested exception is: java.net.ConnectException: Connection refused.

I have no idea why the host is here 127.0.1.1 ...

@nos

Of course, I disabled the windows firewall and the protection mechanismn of Kaspersky Internet Security. I don't think that there is a running firewall in my Kubuntu. In generell it is possible to establish a connection, because I already used scp to copy my program to the other machine.

Edit2:

Mhhh, after setting the entry in /etc/hosts which refers to the machine to the ip address of the machine it seems to work, but don't really understand why it does ...

BR,

Markus

A: 

Using different versions of the JDK on each server could cause this problem.

Use the java -version command to make sure that you are using the same version of the jre.

theoverture
No, on both sides there is the same jre package installed (sun-java6-jre):java version "1.6.0_14"Java(TM) SE Runtime Environment (build 1.6.0_14-b08)Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)
Markus
+1  A: 

You need to add an entry to the hosts file of the machines containing an entry of the form

machinename    privateip

e.g.

virtualmachine    192.168.1.16

This will prevent RMI from sending the localhost host name as a 'call me back' address.

To test this approach, run the following code before and after performing the change.

System.out.println(java.net.InetAddress.getLocalHost());

It should output a local address before the changes and a non-local address after the changes.

Robert Munteanu
Mhhh, you are right. If I set this entry everything is working fine, but I think this could only be a workaround. Do you have any idea why it is not possible to set the 'call me back' address by using the property "java.rmi.server.hostname"?
Markus
Nope, no idea. That being said, after using RMI in production, I'd rather have something else instead - the configuration is a bit tough to get correct. And stale RMI stubs rule ;-)
Robert Munteanu