Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用JavaRMI从服务器向客户端发送消息?_Java_Rmi - Fatal编程技术网

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

如何使用JavaRMI从服务器向客户端发送消息?,java,rmi,Java,Rmi,该应用程序是一个用于局域网的项目管理应用程序,它具有项目、任务等对象,因此RMI似乎是一种可行的方法 但当其他客户端触发事件时,它也会向某些客户端发送实时通知。我读到服务器无法跟踪在RMI中连接到它的客户端。因此,作为一种选择,我认为服务器可以连接到客户端,就像事先连接到服务器的客户端一样。是这样做的吗 如果不是,在这种情况下我应该求助于套接字编程吗 如果这是一个愚蠢的问题,请提前道歉。正如Pierre Henry的回答所建议的那样,您可以在RMI中实现一个使用observer设计模式的回调模式

该应用程序是一个用于局域网的项目管理应用程序,它具有项目、任务等对象,因此RMI似乎是一种可行的方法

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

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


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

正如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使用随机端口,但您可以对此进行更改。