Проблема привязки RMI (от Windows RMI Server до реестра Ubuntu RMI) - PullRequest
1 голос
/ 27 октября 2010

У меня есть сервер RMI, который корректно привязывается к реестру 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();
        }
    }

Мой локальный хост работает под управлением 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», а RMIRegistry работает на моем локальном хосте Windows, код работает правильно (код сервера RMI привязывается к реестру RMI). Однако, когда rmiServerHostname является моей удаленной машиной Ubuntu («божество»), я получаю следующее исключение при вызове «rebind»:

 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 (запущенным на моем локальном хосте) и rmiRegistryHostname (запущенным на «божестве»). Я изменил код следующим образом, но все еще получаю ту же проблему (обратите внимание на изменение в строке «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 работает на «божестве», как я хочу, чтобы во время работы RMIServer на моем локальном хосте «RTPC») -16' )
  • Я связывал кодовую базу интерфейса RMI ("ReutersTickHistoryInterface.jar") как на клиенте, так и на сервере, поэтому я не ожидал, что RMI потребуется передавать какие-либо определения классов - RMI просто создает классы-заглушки на клиенте и обрабатывает фактические вызовы RMI

Ответы [ 2 ]

0 голосов
/ 27 октября 2010

Также вы неправильно используете имя java.rmi.server.hostname.Это не то, для чего это.Поскольку этот код привязан к Реестру, и вы можете сделать это только в том случае, если Реестр работает на том же хосте, вы должны просто использовать «localhost» при получении ссылки на реестр для привязки или отмены привязки.

0 голосов
/ 27 октября 2010

Вы получаете это исключение, потому что rmiregistry не может найти заглушки удаленного объекта или другие классы, необходимые заглушке.При запуске сервера необходимо указать свойство java.rmi.server.codebase, которое должно быть местом расположения заглушек реализации.Это необходимо для динамической загрузки класса заглушки в реестр.

Для получения дополнительной информации об этом свойстве обратитесь к Динамическая загрузка кода с использованием учебного пособия RMI .

...