#java #rmi #wan
#java #rmi #глобальная сеть
Вопрос:
На первый взгляд это может показаться основной сетевой проблемой, но я думаю, что это не так. Похоже, что сама Java «игнорирует» соединение RMI.
Все Java 8u101 на ПК с Windows 10.
У нас есть довольно зрелое и надежное распределенное Java-приложение, которое взаимодействует через RMI в локальной сети.
У наших клиентов, которые уже много лет запускают наше приложение в своих локальных сетях, не было никаких проблем. Это же приложение также подключается к общей базе данных (на том же «серверном» ПК, что и сервер RMI).
Один из наших клиентов недавно построил новое здание, возможно, в 100 метрах, и их два помещения соединены через глобальную сеть. Однако клиенты Java на удаленном сайте не могут подключиться к серверу Java RMI.
Кажется, что вся сама сеть в порядке следующим образом….
- в локальной сети все работает как обычно
- Не RMI в порядке:
- из удаленного местоположения мы можем запустить другой клиент базы данных и успешно подключиться к серверу базы данных (на том же компьютере, что и сервер RMI)
- Порт RMI кажется нормальным со стороны клиента
- используя клиент telnet в удаленном местоположении, мы можем установить соединение с портом RMI
- Порт RMI, похоже, подключается к серверному ПК:
- на компьютере, на котором работает сам сервер Java RMI, мы можем наблюдать соединения через «netstat -an», которые показывают установленное соединение, поступающее с соответствующего IP-адреса WAN.
Это указывало (для меня), что соединение попадает в правильное местоположение и не блокируется неправильной конфигурацией, брандмауэром или чем-либо еще. Кажется, что он «входит» в компьютер сервера RMI, но затем не попадает на сам сервер RMI.
Моим первым предположением было попытаться использовать что-то вроде «панели управления Java» и, возможно, настроить параметр безопасности, который может ограничивать трафик RMI, но я не могу распознать ни одного такого переключателя.
Кто-нибудь может предложить какие-либо подсказки по этому поводу?
- любой способ проверить, что соединение попадает на Java?
- может ли это быть Java security, которая блокирует это перед передачей на сервер RMI?
Любые предложения или рекомендации будут высоко оценены.
(Отредактировано, добавлено больше деталей …)
Немного больше информации заключается в следующем…
- в локальной сети серверный компьютер известен как 192.168.0.110
- из удаленного местоположения (через глобальную сеть) серверный КОМПЬЮТЕР известен как 110.142.83.167
- удаленный клиент, похоже, получает объект сервера RMI
- Трассировка стека (подробно описанная ниже) имеет «отказано в подключении к хосту: 192.168.0.110;»
- таким образом, кажется, что существует путаница в отношении того, какой это IP-адрес. Клиент запросил 110.142.83.167, но сервер считает, что это 192.168.0.110
Трассировки стека следующие…
2016-10-18 15:02:11,123 [S38P4][43983 ][AWT-EventQueue-0] WARN StackTraceLogger log: StackTraceLogger ------- INFO=ClientRMIObject.connectToSentry(): RemoteException: sentryIP=110.142.83.167<<
StackTraceLogger ------ Throwable.MSG=Connection refused to host: 192.168.0.110; nested exception is:
java.net.ConnectException: Connection timed out: connect< Throwable=java.rmi.ConnectException: Connection refused to host: 192.168.0.110; nested exception is:
java.net.ConnectException: Connection timed out: connect
StackTraceLogger.START TRACE .................................
sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
sun.rmi.server.UnicastRef.invoke(Unknown Source)
java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
com.sun.proxy.$Proxy13.registerWithSentry(Unknown Source)
com.my.co.package.ClientRMIObject.connectToSentry(ClientRMIObject.java:198)
Following super cut down version (no boiler plate etc) of the code …
На сервере RMI…
// auto called at server on startup ...
public final class MyServer {
public final static int SRVR_PORT = 21099;
public final static String LOOKUP_NAME = "MyLookupName";
public MyServer() {
java.rmi.registry.Registry reg = java.rmi.registry.LocateRegistry.createRegistry(SRVR_PORT);
ServerRMIObject srvrRmiObj = new ServerRMIObject();
reg.rebind(LOOKUP_NAME, srvrRmiObj);
}
}
ServerRMIObject …
public final class ServerRMIObject extends java.rmi.server.UnicastRemoteObject {
private List<ClientRMIObject> clients = ...
public ServerRMIObject() throws java.rmi.RemoteException {
super(MyServer.SRVR_PORT);
}
public void registerWithSrvr(ClientRMIObject client) {
logger.info("This line is never run when called from remote location");
clients.add(client);
}
// example method ...
public void broadcastToClients(Delivery d) {
for (ClientRMIObject client : clients) {
client.receiveFromSrvr(d);
}
}
}
На каждом клиенте RMI…
public final class ClientRMIObject extends java.rmi.server.UnicastRemoteObject {
private final int CLIENT_PORT = 21099;
private final String SRVR_FROM_LAN = "//192.168.0.110:" MyServer.SRVR_PORT "/" MyServer.LOOKUP_NAME;
private final String SRVR_FROM_WAN = "//110.142.83.167:" MyServer.SRVR_PORT "/" MyServer.LOOKUP_NAME;
private ServerRMIObject rmiSrvr = null;
public ClientRMIObject() {
super(CLIENT_PORT);
}
// auto called at client on startup
public void start() {
if (VIA_LAN) {
rmiSrvr = java.rmi.Naming.lookup(SRVR_FROM_LAN);
} else if (VIA_WAN) {
rmiSrvr = java.rmi.Naming.lookup(SRVR_FROM_WAN);
}
// this has been successful to here.
// the following throws an exception ...
// java.rmi.ConnectException: Connection refused to host: 192.168.0.110;
// please see more exception details above
rmiSrvr.registerWithSrvr(this);
}
// example method ...
public void receiveFromSrvr(Delivery d) {
....
}
// example broadcast from one client to all clients ...
public void broadcastToClients(Delivery d) {
rmiSrvr.broadcastToClients(d);
}
}
Комментарии:
1. Определите «не удается подключиться». Что происходит вместо этого?
2. вы явно указали оба порта rmi?
3. Спасибо EJP и jtahlborn за ваши ответы.
4. Woops, слишком быстрое нажатие кнопки ввода …. jtahlborn: я полагаю, что я указал оба порта (на стороне клиента * сервера) EJP: я добавил более подробную информацию в вопрос, включая местоположение исключения.
5. Я не вижу никакого кода, который
registerWithSentry()
где-либо вызывается, и я также не вижу никаких удаленных интерфейсов или удаленных объектов, которые их реализуют. Это еще не правильный RMI.
Ответ №1:
Мы столкнулись с аналогичной проблемой, когда обновили серверные компьютеры RMI до WINDOWS 10.
Это исключение связано с тем, что брандмауэр Windows Windows10, на котором запущен сервер, не разрешает трафик на порты по протоколу TCP.
Чтобы включить брандмауэр windows10 для TCP, нам нужно выполнить следующие действия: 1. Откройте панель управления 2. Брандмауэр Windows -> Дополнительные настройки 3. Выберите правила входящих сообщений 4. В правом столбце -> опция нового правила 5. Создайте правило порта и создайте как правило TCP, так и UDP, оба — локальный порт 1099 / Все порты 6. В разделе действий нажмите «разрешить соединение» 7. Проверьте все, где применяется правило
Ответ №2:
Из https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/javarmiproperties.html
java.rmi.server.hostname
Значение этого свойства представляет строку имени хоста, которая должна быть связана с удаленными заглушками для локально созданных удаленных объектов, чтобы позволить клиентам вызывать методы на удаленном объекте. Значением этого свойства по умолчанию является IP-адрес локального хоста в формате «dotted-quad».
Реестр RMI сообщает клиенту IP-адрес (или имя хоста) и порт, к которому клиент может затем подключиться для вызова удаленного объекта. По умолчанию он использует адрес локального хоста.
Ваш сервер настроен с IP-адресом 192.168.0.110
, и, следовательно, это то, о чем сообщает реестр RMI. Реестр RMI не знает, что вы хотите получить доступ к компьютеру через какой-либо другой IP-адрес (а именно общедоступный маршрутизируемый 110.142.83.167
— и при этом разумно не знать, так ли это, что брандмауэр выполняет преобразование сетевых адресов).
Разговор идет так:
- Клиент WAN подключается к реестру RMI по адресу
110.142.83.167
. - Клиент WAN запрашивает: Я хотел бы знать, как общаться с объектом
Foo
- Отчеты реестра RMI: вы можете связаться
Foo
с192.168.0.110:<some port>
- Клиент WAN пытается подключиться
192.168.0.110:<some port>
, но эта машина недоступна
Вы можете установить java.rmi.server.hostname
явное значение (например, 110.142.83.167
), но обратите внимание, что тогда все клиенты будут пытаться подключиться к удаленным объектам, используя этот IP-адрес.
Одним из способов решения этой проблемы является использование имени хоста и разделенной системы DNS, в которой внешние клиенты разрешают имя хоста 110.142.83.167
, а внутренние клиенты разрешают имя хоста 192.168.0.110
. (В качестве альтернативы вы можете использовать запись файла hosts на клиентских компьютерах, но это становится проблемой в административном отношении, если количество клиентских компьютеров велико).
Также обратите внимание, что если вы явно не привязали удаленный объект к определенному порту, тогда будет использоваться эфемерный порт — поэтому вам понадобится ваш брандмауэр, чтобы разрешить доступ ко всем портам. Привязав удаленный объект к определенному порту, ваш брандмауэр может быть настроен так, чтобы пропускать только этот порт (плюс порт реестра).
Комментарии:
1. Спасибо, Грег. Уточнение… При создании ServerRMIObject «жестко» устанавливается как «My-IP = 192.168.0.110 и My-Port = 21099». Затем удаленный клиент получает ServerRMIObject из реестра, и ServerRMIObject по-прежнему считает «My-IP = 192.168.0.110 и My-Port = 21099». Итак, теперь мне нужно, чтобы удаленный клиент «перехватил» вызов 192.168.0.110 (IP-адрес сервера в локальной сети) и вместо этого перенаправил его на 110.142.83.167 (IP-адрес сервера в глобальной сети). Если да, возможно ли это с помощью таблиц маршрутов и т. Д.? — или это сложнее, чем это? Большое спасибо.
2. @DamianC Что именно вы подразумеваете под «жестким набором»? Метод, описанный в этом ответе, является единственным способом связать IP-адрес, отличный от IP-адреса по умолчанию, с удаленным объектом.