Search code examples
javarmi

RMI starts two servers in localhost but different port at the same time


I'm learning RMI, and wondering that if it is possible to start two servers with different ports, and how to implement it?

The programme has one client and two servers. Server1 uses the RMI default port 1099. Server2 uses the port 1098 (I have checked the port 1098 is not in use).

Server1:

public static void main(String[] args) {
    try {
        Server obj = new Server();
        Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);

        Registry registry = LocateRegistry.getRegistry();
        registry.bind("Hello", stub);

        System.out.println("Server 1 ready");
    } catch (Exception e){
        System.err.println("Server exception: " + e.toString());
        e.printStackTrace();
    }
}

Server2

public static void main(String[] args) {
    try {
        ServerTwo obj = new ServerTwo();
        HelloTwo stub = (HelloTwo) UnicastRemoteObject.exportObject(obj, 0);

        Registry registry = LocateRegistry.createRegistry(1098);
        registry = LocateRegistry.getRegistry(1098); 
        registry.bind("HelloTwo", stub);

        System.out.println("Server 2 ready");
    } catch (Exception e){
        System.err.println("Server exception: " + e.toString());
        e.printStackTrace();
    }
}

Compile and run server:

javac *java
rmic Server
rmiregistry 1099 &
rmic ServerTwo
rmiregistry 1098 &

By the way, the process name in port 1099 and 1098 is different. I checked the port by lsof -i tcp:portnumber and found there are two process in port 1099 and 1098 respectively. But the port 1099 shows the name is *:rmiregistry (LISTEN). The port 1098 shows the name is *:rmiactivation (LISTEN). Why they are different? What does this mean? Does this relate to the following error?

When start the Server2, error is following:

Server exception: java.rmi.server.ExportException: Port already in use: 1098; nested exception is: 
java.net.BindException: Address already in use 
java.rmi.server.ExportException: Port already in use: 1098; nested exception is: 
java.net.BindException: Address already in use
at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:341)
at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:249)
at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:411)
at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:147)
at sun.rmi.server.UnicastServerRef.exportObject(UnicastServerRef.java:208)
at sun.rmi.registry.RegistryImpl.setup(RegistryImpl.java:152)
at sun.rmi.registry.RegistryImpl.<init>(RegistryImpl.java:137)
at java.rmi.registry.LocateRegistry.createRegistry(LocateRegistry.java:203)
at ServerTwo.main(ServerTwo.java:20)
Caused by: java.net.BindException: Address already in use
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:382)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at java.net.ServerSocket.<init>(ServerSocket.java:128)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createServerSocket(RMIDirectSocketFactory.java:45)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createServerSocket(RMIMasterSocketFactory.java:345)
at sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:666)
at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:330)
... 8 more

It shows the port 1098 is in use... Yes, Server2 use the port... how to solve it? I'm confused about the RMI and port connection.

=============

Edit:

Add Client code:

public static void main(String[] args) {
    String host = (args.length < 1) ? null : args[0];

    try {
             Registry registry = LocateRegistry.getRegistry(host);
             Hello stub = (Hello) registry.lookup("Hello");
             String response = stub.sayHello();
             System.out.println("response 1: " + response);

             HelloTwo stub2 = (HelloTwo) registry.lookup("HelloTwo");
             String response2 = stub2.sayHello();
             System.out.println("response 2: " + response2);

    } catch (Exception e) {
        System.err.println("Client exception: " + e.toString());
        e.printStackTrace();
    }
}

Solution

  • You don't need two Registries. You don't even need two ports, if the Registry and the remote obects are all created by the same JVM. You just need to:

    • put both remote objects into the same JVM
    • call LocateRegistry.createRegistry(Registry.REGISTRY_PORT)
    • and then create and export both remote objects.

    In that way, everything will be listening on port 1099.

    The port 1098 shows the name is *:rmiactivation (LISTEN). Why they are different?

    Because port 1098 is reserved for the RMI Activation Daemon, and that is all that lsof knows about it.