2015-03-26 1 views
3

Приложение представляет собой приложение для управления проектами для локальной сети, и в нем есть объекты, такие как Project, Task и т. Д. Таким образом, RMI выглядел как способ.Как отправить сообщение от сервера к клиенту с помощью Java RMI?

Но у него также есть прямые уведомления, отправленные определенным клиентам, поскольку события инициируются другими клиентами. Я читал, что серверы не могут отслеживать клиентов, которые были подключены к нему в RMI. Поэтому, как вариант, я думаю, что сервер мог подключиться к клиенту, как клиент, подключенный к серверу заранее. Так ли это сделано?

Если нет, следует ли прибегать к программированию сокетов в этой ситуации?

Извинения заранее, если это глупый вопрос.

+0

Не могли бы вы сохранить соединение живым, как в http://stackoverflow.com/questions/227276/java-rmi-not-closing-socket-after-lease-expiration – bhantol

+0

@bhantol Этот вопрос не о том, как сохранить живое соединение и сохранение его жизни не является решением этой проблемы. – EJP

+0

@EJP Ну, мой вопрос в том, собирается ли связь, воссоздана или сохранена в живых? Я хотел знать об этом, так как решение, которое я предлагаю, было в строках WebSockets или именно это, а не даже RMI. – bhantol

ответ

7

Вы правы в своем предположении.

Для активного уведомления push-стиля от сервера к клиентам клиенты также должны быть «серверами».

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

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

На сервере хранится реестр всех клиентов, чтобы он мог перезвонить по мере необходимости. Как правило, карта с ключом является значимым идентификатором клиентов, а значение - удаленной ссылкой на клиента.

Когда клиентское приложение отключено, клиенту необходимо отменить регистрацию.

И сервер, вероятно, захочет периодически проверять всех клиентов, чтобы он не хранил ссылки на мертвых клиентов.

Ваш интерфейс сервера будет выглядеть примерно так:

public interface Server extends Remote { 

    void register(Client client) throws RemoteException; 

    void unregister(Client client) throws RemoteException; 

    void doSomethingUseful(...) throws RemoteException; 

    ... 

} 

и ваш клиентский интерфейс:

public interface ClientCallbackInterface extends Remote { 

    void ping() throws RemoteException; 

    void notifyChanges(...) throws RemoteException; 

} 

И где-то в клиентском коде запуска приложения:

ClientCallbackInterface client = new ClientImpl(); 

UnicastRemoteObject.exportObject(client); 

Registry registry = LocateRegistry.getRegistry(serverIp, serverRegistryPort); 

Server server = (Server) registry.lookup(serviceName); 

server.register(client); 

Это вполне возможно его реализовать. Но не тривиально. Есть много вещей, о которых вы должны заботиться:

  • Вы должны позаботиться о том, что может быть проблемой при наличии брандмауэров.
  • Может быть проблемы с местным брандмауэром ОС тоже ваш клиент приложение на самом деле должен открыть местные входящие порты
  • Если вы попытаетесь запустить несколько клиентов на той же машине, вы будете иметь порт конфликта, должны позаботиться о том, что слишком
  • Полностью не будет работать за пределами LAN

Я реализовал такую ​​систему, и она отлично работает. Но все, что сказал, если бы мне пришлось это сделать снова, я бы определенно использовал что-то еще, возможно, REST и WebSockets для обратных вызовов. Это будет гораздо меньше ограничений для сетевой части, просто необходим HTTP.

+0

Приятно это знать. QQ, хотя. Как выполняется обратный вызов. Интерфейс 'Client' расширяет интерфейс ClientCallbackInterface? –

+0

Да, в моем коде была опечатка. Я отредактировал его. Спасибо, что заметили –

+0

@PierreHenry. Помимо проблем с портом, почему «Полностью не собирается работать за пределами локальной сети»? И включает ли LAN VPLAN? –

0

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


На уровне зернистого можно реализовать программирование сокетов и использовать Observer design pattern. Каждый клиент сначала регистрируется на сервере. Сервер будет хранить их в структуре данных, и когда какое-либо уведомление о событии будет отправлено, сервер будет перебирать эти зарегистрированные клиенты и вызывать методы или нажимать на них уведомления.

Рассмотрите возможность использования некоторой версии JMS (Java messaging service), как Active MQ. Ваш отправитель будет асинхронно слушать очередь. Отправитель отправит сообщение, и получатель получит сообщение. Если вы хотите, чтобы все клиенты получали темы использования сообщений вместо очередей, а также будут издатели и подписчики.

+0

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

+0

Причина для downvote? –

+0

Удаленный объект - это сервер, а процесс, который вызывает его удаленные методы, является клиентом. Клиент RMI также может быть сервером: это шаблон обратного вызова. Нет необходимости использовать Сокеты и Наблюдаемые. – EJP