Как я удостоверяюсь, что RMI использует только определенный набор портов?

Как будто вы пытаетесь получить доступ к объекту, который является null. Рассмотрим ниже пример:

TypeA objA;

. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException, что имеет смысл.

См. Также этот пример:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
8
задан Bob Cross 27 January 2009 в 01:29
поделиться

3 ответа

Можно сделать это с пользовательской Фабрикой Сокета RMI.

Фабрики сокета создают сокеты для RMI для использования в обоих конца клиента и сервера поэтому, если Вы пишете свое собственное, у Вас есть полный контроль над используемыми портами. Клиентские фабрики создаются на сервере, Сериализированном и затем отправленном вниз клиенту, который крут.

Вот руководство в Sun, говоря Вам, как сделать это.

3
ответ дан 5 December 2019 в 22:22
поделиться

Сводка длинного ответа ниже: для решения проблемы, которую я имел (ограничение сервера и портов обратного вызова с обоих концов соединения RMI) я должен был создать двух пар фабрик сокета клиента и сервера.

Более длинный ответ следует:

Наше решение проблемы обратного вызова имело по существу три части. Первым было обертывание объекта, для которого была нужна способность указать, что это привыкло для клиента к серверному соединению по сравнению с тем, чтобы быть используемым для сервера к клиентскому обратному вызову. Используя расширение UnicastRemoteObject дал нам способность указать фабрики сокета клиента и сервера, которые мы хотели использовать. Однако лучшее место для блокировки вниз фабрик сокета находится в конструкторе удаленного объекта.

public class RemoteObjectWrapped extends UnicastRemoteObject {
// ....
private RemoteObjectWrapped(final boolean callback) throws RemoteException {
  super((callback ? RemoteConnectionParameters.getCallbackPort() : RemoteConnectionParameters.getServerSidePort()),
        (callback ? CALLBACK_CLIENT_SOCKET_FACTORY : CLIENT_SOCKET_FACTORY),
        (callback ? CALLBACK_SERVER_SOCKET_FACTORY : SERVER_SOCKET_FACTORY));
}
// ....
}

Так, первый аргумент указывает часть, на которой объект ожидает запросы, тогда как второе и третье указывают фабрики сокета, которые будут использоваться с обоих концов соединения, управляющего этим удаленным объектом.

Так как мы хотели ограничить порты, используемые соединением, мы должны были расширить фабрики сокета RMI и заблокировать вниз порты. Вот некоторые эскизы нашего сервера и клиентских фабрик:

public class SpecifiedServerSocketFactory implements RMIServerSocketFactory {
/** Always use this port when specified. */
private int serverPort;
/**
 * @param ignoredPort This port is ignored.  
 * @return a {@link ServerSocket} if we managed to create one on the correct port.
 * @throws java.io.IOException
 */
@Override
public ServerSocket createServerSocket(final int ignoredPort) throws IOException {
    try {
        final ServerSocket serverSocket = new ServerSocket(this.serverPort);
        return serverSocket;
    } catch (IOException ioe) {
        throw new IOException("Failed to open server socket on port " + serverPort, ioe);
    }
}
// ....
}

Обратите внимание, что фабрика сокета сервера выше гарантирует, что только порт, который Вы ранее указали, будет когда-либо использоваться этой фабрикой. Клиентская фабрика сокета должна быть соединена с соответствующей фабрикой сокета (или Вы никогда не будете соединяться).

public class SpecifiedClientSocketFactory implements RMIClientSocketFactory, Serializable {
/** Serialization hint */
public static final long serialVersionUID = 1L;
/** This is the remote port to which we will always connect. */
private int remotePort;
/** Storing the host just for reference. */
private String remoteHost = "HOST NOT YET SET";
// ....
/**
 * @param host The host to which we are trying to connect
 * @param ignoredPort This port is ignored.  
 * @return A new Socket if we managed to create one to the host.
 * @throws java.io.IOException
 */
@Override
public Socket createSocket(final String host, final int ignoredPort) throws IOException {
    try {
        final Socket socket = new Socket(host, remotePort);
        this.remoteHost = host;
        return socket;
    } catch (IOException ioe) {
        throw new IOException("Failed to open a socket back to host " + host + " on port " + remotePort, ioe);
    }
}
// ....
}

Так, единственная вещь, остающаяся вызвать Ваши два способа, которыми соединение для пребывания на том же наборе портов является некоторой логикой, чтобы распознать, что Вы перезваниваете к клиентскому. В той ситуации просто удостоверьтесь, что Ваш метод фабрики для удаленного объекта называет конструктора RemoteObjectWrapper вершиной с набором параметра обратного вызова к истинному.

1
ответ дан 5 December 2019 в 22:22
поделиться

У меня были различные проблемы с реализацией архитектуры RMI Server/Client, с обратными вызовами клиента. Мой сценарий таков, что и сервер и клиент находятся за Firewall/NAT. В конце концов, я получил полностью рабочую реализацию. Вот основные вещи, которые я сделал:

Сторона сервера, локальный IP: 192.168.1.10. Публичный (Интернет) IP 80.80.80.10

На Firewall/Router/Local Server PC открыт порт 6620. На брандмауэре/маршрутизаторе/локальном серверном ПК откройте порт 1099. На маршрутизаторе/НАТ перенаправьте входящие соединения на порт 6620 на 192.168.1.10:6620 На Router/NAT перенаправить входящие соединения по порту 1099 на 192.168.1.10:1099

В реальной программе:

System.getProperties().put("java.rmi.server.hostname", IP 80.80.80.10);
MyService rmiserver = new MyService();
MyService stub = (MyService) UnicastRemoteObject.exportObject(rmiserver, 6620);
LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry();
registry.rebind("FAManagerService", stub);

Client Side, Local IP: 10.0.1.123 Public (Internet) IP 70.70.70.20

На Firewall/Router/Local Server PC открыть порт 1999. На маршрутизаторе/НАТ перенаправьте входящие соединения на порт 1999 на 10.0.1.123:1999

В самой программе:

System.getProperties().put("java.rmi.server.hostname", 70.70.70.20);
UnicastRemoteObject.exportObject(this, 1999);
MyService server = (MyService) Naming.lookup("rmi://" + serverIP + "/MyService ");

Надеюсь, это поможет. Iraklis

0
ответ дан 5 December 2019 в 22:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: