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

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

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

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

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

你是对的。

对于从服务器到客户端的主动推送式通知,客户端也必须是“服务器”。

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

此对象需要导出为远程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); 

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

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

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

正如皮埃尔亨利的答案建议你可以实现一个在RMI中使用观察者设计模式的回调模式。


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

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