首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

為 RMI 實現類 Jini 發現機制:多播 UDP + 單播 TCP 代理傳遞

     編輯:Java 相關知識

背景動機

RMI 客戶端需硬編碼服務 URL (rmi://host:port/Name);Jini 透過 Lookup Service 實現服務發現,客戶端無需知曉服務位置。為不重寫現有 RMI 系統,實現輕量級「類 Jini」發現層。

協議設計

多播請求封包格式:RMI-DISCOVERY,回應端口,介面類全名,服務唯一ID

  • 協議頭 RMI-DISCOVERY 過濾雜訊。
  • 客戶端開 ServerSocket 監聽回應端口,發送多播 UDP 封包。
  • 服務端 MulticastSocket 監聽固定群組 (如 228.5.6.7:6789),收到合法封包解析,比對介面與服務 ID。
  • 匹配成功:服務端透過單播 TCP 連回客戶端 ServerSocket,序列化 MarshalledObject 包裝的 Remote Stub 傳遞。
  • 客戶端反序列化 MarshalledObject.get() 獲得 Stub,開始遠端調用。

核心類結構

  • RMILookup (服務端):綁定 Remote 實例與服務 ID,啟動多播監聽線程,處理請求、比對、單播回傳 Stub。
  • RMIDiscovery (客戶端):lookup(Class clazz, String id),啟動單播監聽、多播發送、接收 Stub、返回 Remote 介面。
  • MarshalledObject:攜帶 Stub 序列化數據與 Codebase,解決客戶端無 Stub 類定義時的 ClassNotFoundException。

關鍵代碼片段


// 服務端多播監聽循環
while (active) {
    DatagramPacket pkt = new DatagramPacket(buf, buf.length);
    socket.receive(pkt);
    String msg = new String(pkt.getData()).trim();
    if (msg.startsWith("RMI-DISCOVERY")) {
        String[] parts = parseMsg(msg); // port, interface, serviceId
        if (matchInterface(parts[1]) && matchServiceId(parts[2])) {
            Socket sock = new Socket(pkt.getAddress(), Integer.parseInt(parts[0]));
            new ObjectOutputStream(sock.getOutputStream()).writeObject(new MarshalledObject(remoteStub));
            sock.close();
        }
    }
}

// 客戶端發現
ServerSocket listener = new ServerSocket(0); // 自動分配端口
int port = listener.getLocalPort();
sendMulticast("RMI-DISCOVERY," + port + "," + clazz.getName() + "," + id);
Socket sock = listener.accept();
Remote stub = (Remote) ((MarshalledObject) new ObjectInputStream(sock.getInputStream()).readObject()).get();

限制與建議

  • 多播 UDP 通常限於同一子網,跨 WAN 需 Jini 聯合 Lookup Service。
  • 獨立機器無 Hub 時多播不通,需 Loopback 適配器 (Windows 可能有問題)。
  • 新專案強烈建議直接採用 Jini/Apache River,機制更完善、支援租約、事件、事務等進階特性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved