1

I want to make rmi server on port and network interfaces I choose programmatically (without jvm settings). For example I want the rmi server listen interface 127.0.0.1 and port 2525. I've read information in internet and this is the solution I finally came to.

class ServerSocketFactory implements RMIServerSocketFactory, Serializable {

    public ServerSocket createServerSocket(int port) throws IOException
    {
        ServerSocket server = new ServerSocket(2525, 0, InetAddress.getByName("127.0.0.1"));
        return server;
    }
}

And this is how I create my registy

registry = LocateRegistry.createRegistry(2525,null,new ServerSocketFactory());

However, I get exception:

java.rmi.server.ExportException: Port already in use: 2525; nested exception is: 
    java.net.BindException: Address already in use
    at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:341)

I can't understand why if I use ServerSocketFactory in createRegistry there is also a port argument. What is my mistake?

P.S. This is not duplicate of Remote method invocation port in use because it is about selecting network interface but not port.

Community
  • 1
  • 1
Pavel_K
  • 10,748
  • 13
  • 73
  • 186

1 Answers1

1

That BindException means the port is already in use. So you're running this code twice, or something else is listening at the port.

You don't have to specify the port number twice. Just use the port number that is provided as a parameter to createServerSocket(). It will be the port number you specified when exporting, or zero.

If you are using multiple instances of this socket factory, you need to implement equals() in your socket factory class, such that it returns truefor all instances of this class.

NB RMIServerSocketFactory implementations do not need to be Serializable. As a matter of fact you don't really need your RMIServerSocketFactory implementation class at all other than for binding to 127.0.0.1. Unclear why you would want to do that, as it would mean you are doing all your RMI within the same host, which is pretty futile.

So in summary you need:

registry = LocateRegistry.createRegistry(2525);

and

myObject = new MyRemoteObject(2525);

and

// constructor
public MyRemoteObject(int port) throws RemoteException
{
    super(port);
}

If you need the remote object(s) (including the Registry) to listen at only one local IP address instead of all of them, that's when you need an RMIServerSocketFactory:

public class MyRMIServerSocketFactory implements RMIServerSocketFactory
{
    private InetAddress address;

    public MyRMIServerSocketFactory(InetAddress address)
    {
        this.address = address;
    }

    @Override
    public ServerSocket createServerSocket(int port) throws IOException
    {
        return new ServerSocket(port, 0, address);
    }

    @Override
    public boolean equals(Object that)
    {
        return that != null && this.getClass() == that.getClass() && this.address.equals((MyServerSocketFactory)that).address);
    }
}

To use it:

Registry registry = LocateRegistry.createRegistry(2525, null, new MyServerSocketFactory(address));

and

public MyRemoteObject(int port, InetAddress address) throws RemoteException
{
    super(port, null, new MyServerSocketFactory(address);
}

The rules of this game are that ports are shared between remote objects exported from the same JVM (which can include the Registry) if and only if:

  1. none of them use server socket factories, or all of them use server socket factories that are equal under equals()
  2. they all use the same port number, or zero, or no port number, or all after the first object exported use zero or no port number (when they will share the first one's port). Note that this means that port sharing happens by default, provided (1) is met.
user207421
  • 305,947
  • 44
  • 307
  • 483
  • @downvoter If you think there is something wrong here please state what. But random downvoting that gives the impression that correct answers are incorrect, and so mislead the OP, are not to be tolerated here. – user207421 Jul 26 '16 at 11:02
  • As I found out I get that exception when I after creating registry I do UnicastRemoteObject.export(obj,2525). Can you say how export object to socket I created with createRegistry()? Terrible API to be honest. – Pavel_K Jul 26 '16 at 12:19
  • You've done it. Unclear what you're asking. Of course both the Registry and the remote object have to be in the same JVM if you want port sharing, and they have to use equal socket factories too. Unclear what you think is wrong with the API. – user207421 Jul 26 '16 at 12:23
  • I have rmi server - we speak only about server, let's forget about client at all. Now I have the following tasks:1)create socket I want for RMI 2) create registry on that socket 3) export Remote to that socket. I did tasks 1 and 2. But I don't know how to do 3. – Pavel_K Jul 26 '16 at 12:26
  • I just answered that. You've done it. I would get rid of the socket factory, as already suggested in my answer, and just export both your Registry and your remote object(s) on your port. You don't need step (1) either. – user207421 Jul 26 '16 at 12:27
  • Sorry, I don't see answer in your post. My final point is to defins port and network interface via my code. And following your post I can't do that. – Pavel_K Jul 26 '16 at 12:29
  • See edit. If and only if you need to specify a network interface, you need an `RMIServerSocketFactory`, as per my answer, but also as per my answer, I don't see why you would. I suggest you start without. – user207421 Jul 26 '16 at 12:31
  • How can you see what I need? Did I post the specifications of the program I do? So you don't know why I need it. However, you can conclude that I need it, because I ask it. And again, I don't see how to export object to certain `socket`. Please, note I am speaking about `socket` but not `port`. – Pavel_K Jul 26 '16 at 12:35
  • 'Export object to a certain socket' doesn't make sense. I have told you how to export an object to a certain *port*. If you want to use a specific `RMIServerSocketFactory` you have to specify it in the `super()` line, where you call the appropriate constructor of `UnicastRemoteObject`. – user207421 Jul 26 '16 at 12:37
  • There are situations when one computer has several network interfaces. Every interface has its ports. So I ask in my question how work with rmi with different network interfaces on the same computer. – Pavel_K Jul 26 '16 at 12:40
  • And an `RMIServerSocketFactory` is how you do it, as my answer says. What's the problem now? NB by default an RMI remote object listens at all local network interfaces. – user207421 Jul 26 '16 at 12:41