如何使用JavaRMI从服务器向客户端发送消息?
该应用程序是一个用于局域网的项目管理应用程序,它具有项目、任务等对象,因此RMI似乎是一种可行的方法 但当其他客户端触发事件时,它也会向某些客户端发送实时通知。我读到服务器无法跟踪在RMI中连接到它的客户端。因此,作为一种选择,我认为服务器可以连接到客户端,就像事先连接到服务器的客户端一样。是这样做的吗 如果不是,在这种情况下我应该求助于套接字编程吗如何使用JavaRMI从服务器向客户端发送消息?,java,rmi,Java,Rmi,该应用程序是一个用于局域网的项目管理应用程序,它具有项目、任务等对象,因此RMI似乎是一种可行的方法 但当其他客户端触发事件时,它也会向某些客户端发送实时通知。我读到服务器无法跟踪在RMI中连接到它的客户端。因此,作为一种选择,我认为服务器可以连接到客户端,就像事先连接到服务器的客户端一样。是这样做的吗 如果不是,在这种情况下我应该求助于套接字编程吗 如果这是一个愚蠢的问题,请提前道歉。正如Pierre Henry的回答所建议的那样,您可以在RMI中实现一个使用observer设计模式的回调模式
如果这是一个愚蠢的问题,请提前道歉。正如Pierre Henry的回答所建议的那样,您可以在RMI中实现一个使用observer设计模式的回调模式
在粒度级别上,您可以实现套接字编程并使用
观察者设计模式
。每个客户机将首先在服务器上注册。服务器将它们存储在一个数据结构中,当发送一些事件通知时,服务器将迭代这些已注册的客户机并调用方法或向它们推送通知
考虑使用
JMS(Java消息传递服务)
的一些实现,比如activemq
。您的发件人将异步侦听队列。发送者将发送消息,接收者将接收消息。如果您希望所有客户端都接收消息,请使用主题而不是队列,这样会有发布者和订阅者。您的假设是正确的
对于从服务器到客户端的主动推式通知,客户端也必须是“服务器”
因此,在客户端应用程序中,您还需要有一个远程接口。客户机第一次连接到服务器时,向其传递对远程接口实例的引用
此对象需要作为远程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);
实施它是完全可能的。但并非微不足道。有很多事情你必须要注意:
- 如果涉及防火墙,您必须注意这可能是一个问题
- 本地操作系统防火墙也可能存在问题,您的客户端应用程序实际上必须打开本地传入端口
- 如果您试图在同一台机器上启动多个客户端,您将遇到端口冲突,您也必须注意这一点
- 完全不能在局域网外工作
我确实实现了这样一个系统,它工作得很好。但所有这些都表明,如果我必须再次这样做,我肯定会使用其他东西,可能是
REST
服务和WebSockets
进行回调。这将大大减少对网络部分的限制,只需要HTTP 您能否像@bhantol中那样保持连接的活动状态?这个问题不是关于如何保持连接的活动状态,保持连接的活动状态并不是这个问题的解决方案。@EJP我的问题是关于连接是被删除、重新创建还是保持活动状态?我想知道这一点,因为我提出的解决方案是在WebSocket或确切地说,而不是RMI中。@bhantol什么联系?RMI不公开连接,也不依赖于它们以任何方式保持活动状态。正如我在回答中所写的,您实际上可以用RMI实现观察者模式。然而,我同意JMS(或其他东西)可能是更好的选择。远程对象是服务器,调用其远程方法的进程是客户端。RMI客户端也可以是服务器:这是一种回调模式。无需使用套接字和可观察对象。已修改答案以删除RMI部分的“无法完成”。请添加答案或提供指向您所指回调模式的链接。@Pierrehhenry已经提供了您所需的所有信息。实现RMI回调模式非常简单,注册表和/或LDAP与此无关。你的答案仍然不正确。很高兴知道这一点。不过是QQ。回调是如何执行的。Client
interface是否扩展了ClientCallbackInterface
interface?是的,我的代码中有一个输入错误。我编辑了它。谢谢你noticing@PierreHenry除了端口问题,为什么“完全不在LAN之外工作”?局域网包括VPLAN吗?@Paul:嗯,除了端口问题没有别的,但这是个大问题。如果您可以控制防火墙和可以打开的端口,它将在VPN上工作。默认情况下,RMI使用随机端口,但您可以对此进行更改。