【问题标题】:How to send a message from Server to Client using Java RMI?如何使用 Java RMI 从服务器向客户端发送消息?
【发布时间】:2015-03-26 16:48:24
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你能像stackoverflow.com/questions/227276/…那样保持连接吗
  • @bhantol 这个问题不是关于如何保持连接活跃,保持连接不是解决这个问题的办法。
  • @EJP 我的问题是关于连接是被丢弃并重新创建还是保持活动状态?我想知道这一点,因为我提出的解决方案是在 WebSockets 的行中,或者完全是这样,而不是 RMI。
  • @bhantol 什么连接? RMI 不公开连接,也不依赖它们以任何方式保持活动状态。

标签: java rmi


【解决方案1】:

你的假设是对的。

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

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

该对象需要导出为远程 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。

【讨论】:

  • 很高兴知道这一点。不过QQ。回调是如何执行的。 Client 接口是否扩展ClientCallbackInterface 接口?
  • 是的,我的代码中有错字。我编辑了它。感谢您的关注
  • @PierreHenry 除了端口问题,为什么“完全不能在 LAN 之外工作”?局域网包括VPLAN吗?
  • @Paul:嗯,除了端口问题,没什么,但这是一个大问题。如果您可以控制防火墙和可以打开的端口,它将在 VPN 上运行。默认情况下,RMI 使用随机端口,但您可以更改它。
【解决方案2】:

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


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

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

【讨论】:

  • 正如我在回答中所写,您实际上可以使用 RMI 实现观察者模式。但是我同意 JMS(或其他东西)可能是一个更好的选择。
  • 远程对象是服务器,调用其远程方法的进程是客户端。 RMI 客户端也可能是服务器:这是一种回调模式。不必使用 Sockets 和 Observables。
  • 已修改答案以删除 RMI 部分的“无法完成”。请添加答案或提供指向您所指回调模式的链接。
  • @PierreHenry 已经提供了您需要的所有信息。实现 RMI 回调模式非常微不足道,并且注册表和/或 LDAP 与这种或另一种方式无关。您的整个答案仍然不正确。
猜你喜欢
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 2013-06-24
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多