2015-06-16 2 views
0

Я хочу построить систему так, чтобы: 1. Клиент подключается к серверу 2. Клиент запрашивает порт для сервера 3. Сервер создает удаленный объект для обслуживания Клиента и связывает его с порт 4. возвращение номер порта клиента 5. Клиент подключается к портуRMI реализация Управление сеансом

Мой менеджер сессии/подключение

public class ConnectionManager extends UnicastRemoteObject implements Server 
{ 
public List<ClientHandler> clients = Collections.synchronizedList(new ArrayList<>()); 
public ConnectionManager() throws RemoteException 
{ 
    super(); 
} 

public static final String RMI_ID = "Server"; 

@Override 
public boolean checkConnection() throws RemoteException 
{ 
    return true; 
} 

@Override 
public int getPort(String ip) throws RemoteException 
{ 
    int i = 10000+clients.size()*2; 
    clients.add(new ClientHandler(ip, i)); 
    return i; 
} 
} 

реализация Session

public class ClientHandler extends UnicastRemoteObject implements Transfer 
{ 
Registry rmi; 
Registry reg; 
PrintWriter log; 
public Client client; 
public ClientHandler(String ip, int port) throws RemoteException 
{ 
    super(); 
    try 
    { 
     File f = new File(ip+" "+new Date()+".txt"); 
     log = new PrintWriter(f); 
    }catch (Exception e) 
    { 

     e.printStackTrace(); 
    } 
    rmi = LocateRegistry.createRegistry(port); 
    try 
    { 
     rmi.bind(String.valueOf(port),this); 
    }catch(Exception e) 
    { 
     e.printStackTrace(); 
    } 
} 

Проблема в том, что если объект создается при удаленном вызове, он рассматривается как удаленный источник, поэтому, если вы не находитесь на том же хосте, ему не разрешено связывать его с LocalRegistry. и server throws java.rmi.AccessException Registry.Registry.bind запрещен: исходный IP-адрес является нелокальным хостом.

+0

Код, который вы опубликовали, не компилируется, и при его исправлении он не ведет себя так, как вы описали. – EJP

ответ

2

Проблема, что если объект создается в удаленном вызове, считается удаленного происхождения

неправдой. Это просто неверно. Ты только что это сделал. Не делай этого.

и поэтому, если вы не находитесь на том же хосте, не разрешено связывать его с LocalRegistry.

Но вы находитесь на том же хосте. Конструктор ClientHandler работает на том же хосте, что и ConnectionManager, и он создает Registry, также на том же хосте. На самом деле все это происходит в рамках одной JVM.

и сервер throws java.rmi.AccessException Registry.Registry.bind запрещен: исходный IP-адрес является нелокальным хостом.

Нет, это не так. Я проверил ваш код. После исправления ошибки компиляции это сработало. Не могу воспроизвести.

ОДНАКО

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

Простая реализация ваших требований, используя ваши имена классов, выглядит следующим образом, с определенным количеством догадок, как вы не обеспечивают интерфейс Server:

public interface Server extends Remote 
{ 
    boolean checkConnection() throws RemoteException; 
    Transfer getSession(String ip) throws RemoteException; 
} 

public class ConnectionManager extends UnicastRemoteObject implements Server 
{ 
    public List<ClientHandler> clients = Collections.synchronizedList(new ArrayList<>()); 
    public ConnectionManager() throws RemoteException 
    { 
     super(); 
    } 

    public static final String RMI_ID = "Server"; 

    @Override 
    public boolean checkConnection() throws RemoteException 
    { 
     return true; 
    } 

    @Override 
    public Transfer getSession(String ip) throws RemoteException 
    { 
     ClientHandler ch = new ClientHandler(ip); 
     clients.add(ch); 
     return ch; 
    } 
} 

public class ClientHandler extends UnicastRemoteObject implements Transfer 
{ 
    PrintWriter log; 
    public Client client; 
    public ClientHandler(String ip) throws RemoteException 
    { 
     super(); 
     try 
     { 
      File f = new File(ip+" "+new Date()+".txt"); 
      log = new PrintWriter(f); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

EDIT

It ясно из вашего сообщения и вашего комментария ниже, что вы страдаете от ряда серьезных заблуждений относительно Java RMI:

  • , если удаленный объект создан при удаленном вызове, это не 'считается удаленного источника'
  • Порт, по которому экспортируется объект, не имеет ничего общего с реестром.

    Определяется, когда вы строите объект, который расширяет UnicastRemoteObject, через super(), вызов или когда вы вызываете UnicastRemoteObject.exportObject() для других объектов. Если вы укажете ненулевой номер порта, этот порт используется и может нормально использоваться совместно с другими удаленными объектами. В противном случае, если уже используется порт RMI, он используется совместно с этим объектом, в противном случае получается номер порта, выделенного системой.

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

  • Вам не нужно несколько реестров, работающих на одном хосте. Вы можете использовать один и связать с ним несколько имен.
  • Если вы сначала вызвали LocateRegistry.createRegistry(), все другие удаленные объекты, которые вы экспортируете из этой JVM, могут совместно использовать порт с реестром.
  • Удаленные методы могут возвращать удаленные объекты.

    Реестр является примером: это на самом деле очень немного больше, чем удаленная хэш-карта. Ваши методы тоже могут это сделать. В процессе возврата объекты заменяются их заглушками.

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

Дополнительные указания:

  • Метод сделай ничего не действительно проверить соединение. Также возможно создать новое подключение и проверить это. Соединения на самом деле не существуют в RMI или, по крайней мере, они очень хорошо скрыты от вас, объединены, истекли и т. Д.
  • Вам не нужно передавать IP-адрес клиента. Вы можете получить это на сервере от RemoteServer.getClientHost().
  • Конструктор для ClientHandler не должен ловить IOExceptions внутренне: он должен отправить их вызывающему абоненту, чтобы вызывающий мог знать о проблеме.
+0

Это действительно плохое решение. Объекты, которые вы не связывали с реестром, будут использовать случайный порт в диапазоне 49000+.У меня есть 3 интерфейса, 1 для получения объекта сеанса и 2 для пересылки и обратного вызова. В конце он использует 4 порта, которые я назначил для первоначального поиска, и еще 3 в диапазоне 49000+. Настройка NAT и брандмауэров проблематична. – user3224416

+0

Мусор. Читайте, что я написал. Это решение использует только один порт. Ваше предложение о «объектах, которые вы не связывали с реестром» - это полная фантазия, а не только неправильная, но невозможная. Передача портов происходит * до * привязки, а не после. Вы только что сделали это factoid. Если вы хотите обсудить со мной RMI, не используйте измышления своего собственного проекта. – EJP

Смежные вопросы