【问题标题】:Implementing an RMI system in Java - no such object in table用 Java 实现 RMI 系统 - 表中没有这样的对象
【发布时间】:2023-10-23 14:58:01
【问题描述】:

我正在尝试使用三对客户端/服务器在 Java 中实现一个简单的 RMI 系统。 createDrecord 目前只是一个测试方法。

客户代码:

public class ManagerClient { 

public static void main(String[] args) {
    try{
    System.setSecurityManager(new RMISecurityManager());
    ClinicServerInterface mtlServer = (ClinicServerInterface)Naming.lookup("rmi://localhost:2020/mtl");
    ClinicServerInterface lvlServer = (ClinicServerInterface)Naming.lookup("rmi://localhost:2021/lvl");
    ClinicServerInterface ddoServer = (ClinicServerInterface)Naming.lookup("rmi://localhost:2022/ddo");

    mtlServer.createDRecord("asdf", "asfa", "asda", "as", "asd");

    }catch(Exception e){
        e.printStackTrace();
    }
  }
}

服务器代码:

public class ClinicServer implements ClinicServerInterface { 

private int port;
private String location;

public ClinicServer(int port, String location){
    this.port = port;
    this.location = location;
}

public static void main(String[] args){

    int mtlPort = 2020;
    int lvlPort = 2021;
    int ddoPort = 2022;

    try{
        ClinicServer mtlServer = new ClinicServer(mtlPort, "mtl");
        ClinicServer lvlServer = new ClinicServer(lvlPort, "lvl");
        ClinicServer ddoServer = new ClinicServer(ddoPort, "ddo");

        Remote mtlObj = UnicastRemoteObject.exportObject(mtlServer,mtlPort);
        Remote lvlObj = UnicastRemoteObject.exportObject(lvlServer,lvlPort);
        Remote ddoObj = UnicastRemoteObject.exportObject(ddoServer,ddoPort);

        Registry r = LocateRegistry.createRegistry(2020);

        r.bind("mtl", mtlObj);
        r.bind("lvl", lvlObj);
        r.bind("ddo", ddoObj);


        System.out.println("New Server is up and running!");

    }catch(Exception e){

        e.printStackTrace();
    }

}

@Override
public void createDRecord(String firstName, String lastName, String address, String phone, String specialization)
        throws RemoteException {
    System.out.println("Create D Record");

}

服务器运行良好,显示消息,但是当我运行客户端时,我得到这个错误:

java.rmi.NoSuchObjectException: no such object in table
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
    at java.rmi.Naming.lookup(Unknown Source)
    at assignment1.ManagerClient.main(ManagerClient.java:36)

第 36 行是 ManagerClient 类中的这一行:

ClinicServerInterface lvlServer = (ClinicServerInterface)Naming.lookup("rmi://localhost:2021/lvl");

我在这里阅读了其他有类似问题的线程,但似乎无法弄清楚它是如何具体应用于我的代码的。

【问题讨论】:

  • 当您启动服务器时,您是否收到“New Server is up and running”消息?我的意思是服务器运行正常吗?
  • 好的,所以在客户端代码中,我在 Naming.lookup() 方法中将所有端口更改为 2020,它执行得很好。那么该方法参数中的端口号应该是注册表的端口还是远程服务器的端口?
  • @Moolerian 感谢您的快速回复

标签: java rmi distributed-computing


【解决方案1】:

我在 Naming.lookup() 方法中将所有端口更改为 2020 并且它执行得很好。我认为这个方法将服务器端口号作为参数,而不是注册表端口号。

【讨论】:

  • 这本身并不能解决NoSuchObjectException
  • 它仍然可以在服务器类中使用不同的端口,但感谢反馈,我将所有端口更改为 2020。所以只要所有类都在同一个可执行文件中,它们就可以共享同一个端口?
  • 只要它们都是由同一个JVM进程导出的,并且没有套接字工厂,或者相等的套接字工厂。
【解决方案2】:
int mtlPort = 2020;
int lvlPort = 2021;
int ddoPort = 2022;

您不需要为不同的远程对象使用不同的端口号。您可以将 2020 用于所有这些,也可以使用 Registry。

Registry r = LocateRegistry.createRegistry(2020);

您需要将此变量设为静态。否则它可能会被垃圾收集,这也会导致服务器的垃圾收集,这就是导致这个问题的原因。

 System.setSecurityManager(new RMISecurityManager());

除非您使用的是 RMI 代码库功能,否则您不需要客户端中的安全管理器,而您的问题中没有提到这一点。

ClinicServerInterface lvlServer = (ClinicServerInterface)Naming.lookup("rmi://localhost:2021/lvl");

这将得到一个java.rmi.ConnectException,因为端口号不是 2020。

【讨论】:

    最近更新 更多