RMI не может подключиться к удаленному серверу

Недавно я работал с RMI, и хотя мне удалось заставить его работать на локахосте, у меня были всевозможные проблемы при попытке использовать удаленный сервер. Вот основной код, который я пытаюсь запустить:

Сервер:

public class RmiServer extends UnicastRemoteObject implements RmiServerIntf {
    public static final String MESSAGE = "Hello world";

    public RmiServer() throws RemoteException {
    }

    public String getMessage() {
    return MESSAGE;
    }

    public static void main(String args[]) {
        System.out.println("RMI server started");

        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
            System.out.println("Security manager installed.");
            } else {
                   System.out.println("Security manager already exists.");
            }

            try {
                    LocateRegistry.createRegistry(1099);
                    System.out.println("java RMI registry created.");
            } catch (RemoteException e) {
                    e.printStackTrace();
            }

            try {
                    RmiServer obj = new RmiServer();

                    Naming.rebind("rmi://localhost/RmiServer", obj);

                    System.out.println("PeerServer bound in registry");
            } catch (Exception e) {
                    e.printStackTrace();
            }
      }
}

Интерфейс удаленного класса:

public interface RmiServerIntf extends Remote {
    public String getMessage() throws RemoteException;
}

Клиент:

public class RmiClient { 
    RmiServerIntf obj = null; 

    public String getMessage() { 
        try { 
            obj = (RmiServerIntf)Naming.lookup("rmi://54.229.66.xxx/RmiServer");
            return obj.getMessage(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
            return e.getMessage();
        } 
    } 

    public static void main(String args[]) {
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }

        RmiClient cli = new RmiClient();

        System.out.println(cli.getMessage());
    }
}

файл rmi.policy:

grant {
permission java.security.AllPermission;
};

Я скомпилировал классы и создал заглушку для сервера. Затем я разместил клиент, заглушку, интерфейс и политику на своей машине, а сервер, заглушку, интерфейс и политику на удаленной машине. Удаленный сервер, являющийся машиной Linux, я сделал все файлы исполняемыми. Я также добавил правило локального брандмауэра, разрешающее порт 1099, и открыл все порты на удаленной машине.

После этого я перешел в каталог сервера на удаленной машине и вставил следующую команду:

java -Djava.security.policy=rmi.policy RmiServer

Это не доставило мне проблем, поэтому я вернулся к локальной машине и ввел

java -Djava.security.policy=rmi.policy RmiClient

Я жду, и жду, и я получаю сообщение об ошибке:

Connection refused to host: 172.31.xx.xx; nested exception is: java.net.ConnectException: Connection timed out: connect 

Я вчера весь день боролся с этими ошибками подключения, и это все, что я получил. Я уверен, что есть только одна очень маленькая вещь, которую я все еще делаю неправильно, но я просто не могу найти, что это такое.


person spacitron    schedule 16.07.2013    source источник
comment
Можете ли вы подключиться к любому порту на удаленной машине, используя, например, телнет?   -  person    schedule 16.07.2013
comment
Да, у меня нет проблем с другими типами соединений. Я без проблем использовал порт 22, 80 или 11111 (JPPF).   -  person spacitron    schedule 16.07.2013
comment
Ваш клиентский код имеет IP-адрес, отличный от сообщения об отказе в подключении, поэтому может помочь следующее: stackoverflow.com/questions/3071376/   -  person    schedule 16.07.2013


Ответы (2)


Это может не решить вашу проблему, но у меня были похожие проблемы с JPPF (через Java RMI) в Linux. Решение состояло в том, чтобы гарантировать, что временный диапазон портов на клиентской машине покрывает только те порты, которые разрешены локальным брандмауэром клиентской стороны. Например, если ваш брандмауэр позволяет внешним компьютерам подключаться к портам с 48000 по 64000, убедитесь, что ваш эфемерный диапазон портов также находится в пределах от 48000 до 64000. Попробуйте и сообщите нам, что произойдет.

person CodeBlind    schedule 16.07.2013
comment
+1, но реестр вообще не «передает соединения». Он не вызывается на этапе подключения. Что действительно происходит, так это то, что если вы не укажете порт при экспорте удаленного объекта, он прослушивает эфемерный порт. - person user207421; 17.07.2013
comment
Я не говорю конкретно о реестре, я говорю о базовых сетевых механизмах, используемых для обслуживания этого реестра. Под капотом RMI использует ServerSocket и Socket. ServerSocket определенно прослушивает определенный порт и после первоначального рукопожатия с клиентом передает всю последующую связь с этим клиентом Socket, который прослушивает совершенно другой эфемерный номер порта, независимо от того, какой номер порта вы выбрали для своего ServerSocket слушайте. - person CodeBlind; 17.07.2013
comment
Вы ошибаетесь. ServerSocket возвращает сокеты, чей локальный номер порта то же самое, что и номер порта прослушивания. Поэтому, если вы экспортируете объект RMI на фиксированный порт, все подключения к этому объекту будут использовать этот порт. Причина, по которой эфемерные поэты появляются в RMI, заключается в том, что при экспорте не указывается ненулевой номер порта, например. через супер(внутренний порт). - person user207421; 18.07.2013
comment
Моя ошибка на самом деле. Мое первое знакомство с RMI было в проекте, в котором использовались настраиваемые фабрики ServerSocket и Socket, которые вели себя описанным мной способом передачи - мы сделали это, чтобы злоумышленнику было труднее перехватить конкретное клиентское соединение - но это было давно, поэтому я принял это за поведение RMI по умолчанию. - person CodeBlind; 18.07.2013
comment
Я не понимаю, как это вообще возможно, если только вы не использовали дополнительные прослушивающие сокеты на эфемерных портах. Я предполагаю, что ваше воспоминание также ошибочно. Я также предлагаю вам исправить свой ответ. - person user207421; 18.07.2013
comment
... если вы не использовали дополнительные прослушивающие сокеты на эфемерных портах - именно так это было реализовано. Ответ исправлен. - person CodeBlind; 18.07.2013

System.setProperty("java.rmi.server.hostname","10.0.3.73");

Пожалуйста, используйте приведенные выше операторы в стороннем коде RMIServer и попробуйте снова подключиться с удаленного клиента. Это сработало для меня

person JokerKnight    schedule 16.12.2016
comment
Это сработало для вас на этом IP-адресе, потому что это один из ваших IP-адресов. В нем нет ничего такого, что гарантированно сработало бы для всех. - person user207421; 16.12.2016