RMI绑定问题(从Windows RMI服务器到Ubuntu RMI注册表)

时间:2010-10-27 07:07:16

标签: java rmi openjdk rmiregistry

我有一个RMI服务器在localhost上运行时正确绑定到RMI注册表(以证明事情设置正确)。执行此操作的代码是:

 private void exposeTickHistoryRemoteProvider(TickHistoryRemoteInterface aTickHistoryServer) {
        if (System.getSecurityManager() == null) {
            SecurityManager mySecurityManager = getSecurityManager();
   System.setSecurityManager(mySecurityManager);
        }
  String rmiServerHostname = System.getProperties().getProperty("java.rmi.server.hostname");
  try {
   TickHistoryRemoteInterface stub =
                (TickHistoryRemoteInterface) UnicastRemoteObject.exportObject(aTickHistoryServer, 0);
            Registry registry = LocateRegistry.getRegistry(rmiServerHostname);
            String[] services = registry.list();
            registry.rebind(RMI_SERVICENAME_REUTERS_TICKHISTORY_SERVER, stub);
            log.info(RMI_SERVICENAME_REUTERS_TICKHISTORY_SERVER + " bound");
        } catch (Exception e) {
         log.error(RMI_SERVICENAME_REUTERS_TICKHISTORY_SERVER + " exception:" + e.toString());
            e.printStackTrace();
        }
    }

我的localhost正在运行Windows,其中包含以下版本的Java:

C:\eclipse>java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode)

现在,我的问题是我想绑定到在不同机器上运行的RMIRegistry(运行Ubuntu 10.04,使用OpenJDK IcedTea6 1.8.1,java版本1.6.0_18)。

在这个Ubuntu机器上,我的CLASSPATH中没有任何内容(echo $ CLASSPATH),并且正在运行OpenJDK RMIRegistry(而不是与Ubuntu捆绑的那个):

sudo /usr/lib/jvm/java-6-openjdk/jre/bin/rmiregistry &

现在,在上面的代码中,当变量rmiServerHostname为“localhost”且在我的Windows localhost上运行RMIRegistry时,代码正常工作(RMI服务器代码绑定到RMI注册表)。但是,当rmiServerHostname是我的远程Ubuntu机器(“deity”)时,我在“重新绑定”调用上抛出以下异常:

 java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
 java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
 java.lang.ClassNotFoundException: com.relative.tickhistory.provider.TickHistoryRemoteInterface
 java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
 java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
 java.lang.ClassNotFoundException: com.relative.tickhistory.provider.TickHistoryRemoteInterface

如果我杀了RMIRegistry,我会得到一个不同的错误信息(我希望):

 java.rmi.ConnectException: Connection refused to host: deity; nested exception is: 
 java.net.ConnectException: Connection refused: connect
 at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
 at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
 at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
 at sun.rmi.server.UnicastRef.newCall(Unknown Source)
 at sun.rmi.registry.RegistryImpl_Stub.list(Unknown Source)

我认为RMIRegistry(Windows Java6和Ubuntu OpenJDK 6)的这些实现之间没有不兼容性......但是,我不确定如何找到这个实现的底部。特别是因为我知道代码正常工作(在第一个Windows / localhost中)。


迄今为止的进展

非常感谢您的回复。我知道我在rmiServerHostname(在我的localhost上运行)和rmiRegistryHostname(在'deity'上运行)之间感到困惑。我修改了代码,但是仍然遇到了同样的问题(请注意“Registry registry = LocateRegistry.getRegistry( rmiRegistryHostname )”行中的更改):

    String rmiServerCodebase = System.getProperties().getProperty("java.rmi.server.codebase");
    String rmiServerHostname = System.getProperties().getProperty("java.rmi.server.hostname");
    String rmiRegistryHostname = "deity";
    System.out.println("rmiServerCodebase=" + rmiServerCodebase + "; rmiServerHostname=" + rmiServerHostname);
    try {
        TickHistoryRemoteInterface stub =
            (TickHistoryRemoteInterface) UnicastRemoteObject.exportObject(aTickHistoryServer, 0);
        Registry registry = LocateRegistry.getRegistry(rmiRegistryHostname);

print语句的输出是(注意,我的localhost是'RTPC-16')

"rmiServerCodebase=file:///C:/workspace/DEV/ReutersTickHistoryServer/ReutersTickHistoryInterface.jar; rmiServerHostname=RTPC-16"

此文件确实存在:

C:\>dir c:\workspace\DEV\ReutersTickHistoryServer\ReutersTickHistoryInterface.jar
 Volume in drive C is OS
 Volume Serial Number is 7AEB-A105

 Directory of c:\workspace\DEV\ReutersTickHistoryServer

22/10/2010  12:21 PM             9,467 ReutersTickHistoryInterface.jar
               1 File(s)          9,467 bytes

所以,再次总结一下:

  • 当RMIRegistry和RMIServer位于同一物理主机(例如localhost)上时,此代码有效
  • 当我尝试在单独的主机上运行 RMIRegistry进程时出现问题(例如,RMIRegistry正在'deity'上运行,因为我希望它在我的本地主机上运行时是RMIServer' RTPC-16' )
  • 我在客户端和服务器上捆绑了RMI接口代码库(“ReutersTickHistoryInterface.jar”),所以我没想到RMI需要传输任何类定义--RMI只是在客户端上创建存根类并处理实际的RMI调用

2 个答案:

答案 0 :(得分:0)

此外,您滥用java.rmi.server.hostname。这不是它的用途。由于此代码绑定到注册表,并且只有在注册表在同一主机中运行时才能执行此操作,因此在获取用于绑定或解除绑定的注册表引用时,应使用“localhost”。

答案 1 :(得分:-1)

您将收到此异常,因为rmiregistry无法找到远程对象的存根或存根所需的其他类。启动服务器时需要指定java.rmi.server.codebase属性,将其设置为实现存根的位置。这是必需的,以便可以将存根类动态下载到注册表中。

有关此属性的更多详细信息,请查看Dynamic code downloading using RMI教程。