RMI 在 localhost 中同时启动两个服务器,但端口不同

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

我正在学习RMI,想知道是否可以启动不同端口的两个服务器,如何实现?

该程序有一个客户端和两个服务器。 Server1 使用 RMI 默认端口 1099。Server2 使用端口 1098(我检查过 1098 端口没有被使用)。

服务器 1:

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();
    }
}

服务器 2

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();
    }
}

编译和运行服务器:

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

对了,1099和1098端口的进程名不一样。 我通过lsof -i tcp:portnumber查看端口,发现1099和1098端口分别有两个进程。但是1099端口显示名字是*:rmiregistry (LISTEN)。 1098端口显示名字是*:rmiactivation (LISTEN)。为什么他们不同?这是什么意思?这是否与以下错误有关?

启动Server2时,报错如下:

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

显示端口1098正在使用中...是的,Server2正在使用该端口...如何解决?我对 RMI 和端口连接感到困惑。

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

编辑:

添加客户端代码:

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();
    }
}

您不需要两个注册表。如果注册表和远程对象都是由同一个 JVM 创建的,那么您甚至不需要两个端口。您只需要:

  • 将两个远程对象放入同一个 JVM
  • 致电LocateRegistry.createRegistry(Registry.REGISTRY_PORT)
  • 然后创建并导出两个远程对象。

这样一来,所有的东西都会监听1099端口。

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

因为端口 1098 是为 RMI 激活守护程序保留的,这就是 lsof 所知道的全部内容。