簡體   English   中英

如何使用Java RMI從服務器向客戶端發送消息?

[英]How to send a message from Server to Client using 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)一些實現。 您的發件人將異步收聽隊列。 發件人將發送消息,接收者將收到消息。 如果您希望所有客戶端都接收消息使用主題而不是隊列,則會有發布者和訂閱者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM