如何使用Java RMI从服务器向客户端发送消息?

时间:2015-03-26 16:48:24

标签: java rmi

该应用程序是LAN的项目管理应用程序,它有项目,任务等对象。所以RMI似乎是要走的路。

但是,当其他客户端触发事件时,它还会向某些客户端发送实时通知。我读到服务器无法跟踪已在RMI中连接到它的客户端。因此,作为一个选项,我认为服务器可以像预先连接到服务器的客户端一样连接到客户端。这是怎么做的?

如果没有,我应该在这种情况下使用套接字编程吗?

如果这是一个愚蠢的问题,请提前道歉。

2 个答案:

答案 0 :(得分:11)

你是对的。

对于从服务器到客户端的主动推送式通知,客户端必须是"服务器"还

因此,在客户端应用程序中,您还需要一个远程接口。客户端第一次连接到服务器时,会向其传递对远程接口实例的引用。

此对象需要作为远程RMI对象导出,但不需要在注册表中注册,因为您将直接将对它的引用传递给需要在其上调用方法的服务器。

服务器保留所有客户端的注册表,以便在需要时回调。通常是一个Map,其中键是客户端的有意义标识符,值是客户端的远程引用。

当客户端应用关闭时,客户端需要取消注册。

并且服务器可能希望定期检查所有客户端,因此它不会保留对死客户端的引用。

您的服务器界面看起来像这样:

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);

完全可以实现它。但不是微不足道的。你需要照顾很多事情:

  • 如果涉及防火墙,您必须注意哪个可能有问题。
  • 也可能是本地操作系统防火墙出现问题,您的客户端应用程序实际上必须打开本地传入端口
  • 如果您尝试在同一台计算机上启动多个客户端,则会发生端口冲突,也必须处理此问题
  • 完全没有在局域网外工作

我确实实现了这样的系统并且工作正常。但所有这些说,如果我不得不再次这样做,我肯定会使用其他东西,可能是REST服务和WebSockets来进行回调。它对网络部分的限制要少得多,只需要HTTP。

答案 1 :(得分:0)

正如Pierre Henry的回答所建议的那样,你可以实现一个在RMI中使用观察者设计模式的回调模式。


在粒度级别,您可以实现套接字编程并使用Observer design pattern。每个客户端将首先注册到服务器。服务器将它们存储在数据结构中,当要发送某些事件通知时,服务器将遍历这些已注册的客户端并调用方法或向其发送通知。

考虑使用JMS (Java messaging service)的某些实现,例如Active MQ。您的发件人将异步收听队列。发件人将发送消息,接收者将收到消息。如果您希望所有客户端都接收消息使用主题而不是队列,则会有发布者和订阅者。