У меня есть сервер 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