2016-07-26 11 views
1

Я хочу сделать rmi-сервер на портовых и сетевых интерфейсах. Я выбираю программно (без настроек jvm). Например, я хочу, чтобы интерфейс администратора rmi 127.0.0.1 и порт 2525. Я читал информацию в Интернете, и это решение, к которому я наконец пришел.RMI: создать сервер на определенном сетевом адресе и порту

class ServerSocketFactory implements RMIServerSocketFactory, Serializable { 

    public ServerSocket createServerSocket(int port) throws IOException 
    { 
     ServerSocket server = new ServerSocket(2525, 0, InetAddress.getByName("127.0.0.1")); 
     return server; 
    } 
} 

И это, как я создаю мой registy

registry = LocateRegistry.createRegistry(2525,null,new ServerSocketFactory()); 

Однако я получаю исключение:

java.rmi.server.ExportException: Port already in use: 2525; nested exception is: 
    java.net.BindException: Address already in use 
    at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:341) 

Я не могу понять, почему, если я использую ServerSocketFactory в createRegistry есть также аргумент порта. Какая у меня ошибка?

P.S. Это не дублируется Remote method invocation port in use, потому что речь идет о выборе сетевого интерфейса, но не о порте.

+0

@ close-voter Не дубликат этого вопроса .. – EJP

ответ

1

Это BindException означает, что порт уже используется. Таким образом, вы запускаете этот код дважды, или что-то еще слушает в порту.

Вам не нужно указывать номер порта дважды. Просто используйте номер порта, который предоставляется в качестве параметра: createServerSocket(). Это будет номер порта, который вы указали при экспорте, или ноль.

Если вы используете несколько экземпляров этой фабрики сокетов, вам необходимо реализовать equals() в вашем классе фабрик сокетов, чтобы он возвращал true для всех экземпляров этого класса.

NB RMIServerSocketFactory Реализация не обязательно должна быть Serializable. На самом деле вам действительно не нужен ваш класс реализации RMIServerSocketFactory вообще, кроме привязки к 127.0.0.1. Непонятно, почему вы хотели бы сделать это, так как это означало бы, что вы делаете все свои RMI внутри одного и того же хоста, что довольно бесполезно.

Так что в итоге вам нужно:

registry = LocateRegistry.createRegistry(2525); 

и

myObject = new MyRemoteObject(2525); 

и

// constructor 
public MyRemoteObject(int port) throws RemoteException 
{ 
    super(port); 
} 

Если вам нужен удаленный объект (ы) (в том числе реестр) для прослушивания в только один локальный IP-адрес вместо всех из них, тогда вам понадобится RMIServerSocketFactory:

public class MyRMIServerSocketFactory implements RMIServerSocketFactory 
{ 
    private InetAddress address; 

    public MyRMIServerSocketFactory(InetAddress address) 
    { 
     this.address = address; 
    } 

    @Override 
    public ServerSocket createServerSocket(int port) throws IOException 
    { 
     return new ServerSocket(port, 0, address); 
    } 

    @Override 
    public boolean equals(Object that) 
    { 
     return that != null && this.getClass() == that.getClass() && this.address.equals((MyServerSocketFactory)that).address); 
    } 
} 

Для того, чтобы использовать его:

Registry registry = LocateRegistry.createRegistry(2525, null, new MyServerSocketFactory(address)); 

и

public MyRemoteObject(int port, InetAddress address) throws RemoteException 
{ 
    super(port, null, new MyServerSocketFactory(address); 
} 

правилам этой игры является то, что порты разделены между удаленными объектами, экспортируемых из одной и той же виртуальной машины Java (который может включать в реестр) тогда и только тогда, когда:

  1. Никто из них не использует серверную социальную сеть ket или все они используют фабрики серверных сокетов, которые равны equals()
  2. все они используют один и тот же номер порта или ноль или номер порта или все после первого экспортированного объекта используют нулевой номер или номер порта (когда они делят первый порт). Обратите внимание, что это означает, что совместное использование портов происходит по умолчанию, если выполнено (1).
+0

@downvoter Если вы считаете, что что-то не так, пожалуйста, укажите, что. Но случайное downvoting, которое создает впечатление, что правильные ответы неверны, и поэтому вводить в заблуждение OP, здесь нельзя допускать. – EJP

+0

Как я узнал, я получаю это исключение, когда после создания реестра я делаю UnicastRemoteObject.export (obj, 2525). Можете ли вы сказать, как экспортировать объект в сокет, который я создал с помощью createRegistry()? Ужасный API, если честно. –

+0

Вы это сделали. Неясно, что вы спрашиваете. Конечно, и реестр, и удаленный объект должны находиться в одной JVM, если вы хотите использовать порты, и им также нужно использовать одинаковые фабрики сокетов. Неясно, что вы считаете неправильным с API. – EJP