JavaRush /Java Blog /Random-TW /RMI:使用實踐

RMI:使用實踐

在 Random-TW 群組發布
你好!今天我們來看看一個比較有趣的話題—RMI。這代表遠端方法呼叫RMI:使用實務 - 1透過 RMI,您可以教導兩個程式相互通信,即使它們位於不同的電腦上。聽起來很酷嗎?:) 但這並不難做到!在今天的講座中,我們將了解 RMI 互動由哪些部分組成以及如何配置它。我們首先需要一個客戶端一個伺服器。您不必太深入地了解計算機術語。對於 RMI,這只是兩個程式。其中一個將包含某個對象,第二個將呼叫該對象的方法。呼叫一個程式中位於另一個程式中的物件的方法 - 我們以前從未這樣做過!是時候嘗試一下了!:) 為了不被淹沒在荒野中,讓我們的程序變得簡單。一般來說,伺服器通常執行客戶端請求的某種計算。對我們來說也是一樣。我們將有一個簡單的計算器程式作為伺服器。她只有一個方法—— multiply()。它將客戶端程式發送給它的兩個數字相乘並傳回結果。首先我們需要一個介面:
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
為什麼我們需要一個介面?事實上,RMI 的工作是基於創建代理,您在之前的講座中學習過這一點。您可能還記得,代理程式的工作是在介面層級而不是類別層級上精確執行的。我們的介面有兩個重要的要求!
  1. 它必須繼承遠端令牌介面。
  2. 它的所有方法都必須拋出 RemoteException(這不會在 IDE 中自動完成,您必須手動編寫!)。
現在我們需要建立一個伺服器類別來實作我們的介面CalculatorRMI:使用實務 - 2這裡的一切也很簡單:
import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
這裡沒有太多可評論的:)現在我們需要編寫一個伺服器程式來配置和啟動我們的伺服器計算器類別。它看起來像這樣:
import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
讓我們弄清楚:) 在第一行中,我們創建某種字串變數:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
該字串是遠端物件的唯一名稱。透過這個名稱,客戶端程式將能夠找到我們的伺服器:稍後您將看到這一點。接下來我們建立計算器物件:
final RemoteCalculationServer server = new RemoteCalculationServer();
這裡一切都清楚了。下面這個就比較有趣了:
final Registry registry = LocateRegistry.createRegistry(2732);
這個叫做Registry的東西是已刪除物件的註冊表。「刪除」並不是指我們從電腦中刪除它們,而是事實上可以從其他程式遠端存取該暫存器中的物件:)LocateRegistry.createRegistry()我們將數字 2732 傳遞給該方法。這是連接埠號碼。如果您不知道連接埠是什麼,可以在這裡閱讀,但現在您只需要記住這是一個唯一的編號,其他程式可以透過它找到我們的物件註冊表(您也將在下面看到這一點)。讓我們繼續。讓我們看看下一行會發生什麼:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
在這一行我們創建一個存根存根將整個遠端呼叫過程封裝在其內部。可以說這是RMI最重要的元素。她在做什麼?
  1. 接收有關遠端呼叫方法的所有資訊。
  2. 如果該方法有參數,存根會將它們反序列化。注意這一點!傳遞給遠端呼叫方法的參數必須是可序列化的(畢竟,它們將透過網路傳輸)。我們沒有這樣的問題——我們只是傳輸數字。但如果您轉移對象,請不要忘記它!
  3. 之後,它調用所需的方法。
我們將UnicastRemoteObject.exportObject()伺服器計算器物件傳遞給該方法。這樣我們就可以遠端呼叫它的方法。我們只剩下一件事要做:
registry.bind(UNIQUE_BINDING_NAME, stub);
我們用一開始想出的名稱在遠端物件註冊表中「註冊」我們的存根。現在客戶可以找到它了!你可能已經注意到,最後我們讓程式的主執行緒進入睡眠狀態:
Thread.sleep(Integer.MAX_VALUE);
我們只需要保持伺服器長時間運行即可。我們將在 IDEa 中同時執行兩個方法main():第一個是伺服器方法(在我們已經編寫的類別中ServerMain),然後是客戶端方法(在ClientMain我們將在下面編寫的類別中)。重要的是,當我們啟動客戶端時,伺服器程式不會宕機,因此我們只需將其置於休眠狀態很長一段時間即可。它仍然可以工作:) 現在我們可以運行main()我們的伺服器方法。讓它運行並等待客戶端程式調用某個方法:) 現在讓我們編寫一個客戶端程式!它將向我們的伺服器發送數字以進行相乘。
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
她看起來並不複雜。這裡發生了什麼事?首先,客戶端必須知道將遠端呼叫其方法的物件的唯一名稱。因此,在客戶端程式中我們也建立了一個變量,public static final String UNIQUE_BINDING_NAME = "server.calculator"; 接下來,在方法中main()我們可以存取遠端物件的暫存器。為此,我們需要呼叫該方法LocateRegistry.getRegistry()並傳遞在 ServerMain 程式中建立暫存器的連接埠號碼 - 連接埠 2732(選擇此號碼作為範例,您可以嘗試使用另一個號碼):
final Registry registry = LocateRegistry.getRegistry(2732);
現在我們要做的就是從暫存器中取得所需的物件!這很容易,因為我們知道他獨特的名字!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
注意類型轉換。我們將產生的物件轉換為介面Calculator而不是具體的類別 RemoteCalculationServer。正如我們在講座開始時所說的,RMI 是基於代理的使用,因此遠端呼叫僅適用於介面的方法,而不適用於類別。最後,我們遠端呼叫multiply()物件上的方法並將結果列印到控制台。
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
我們很早就main()在類別中啟動了 該方法,現在是時候在客戶端程式中啟動該方法了! 控制台輸出: 600 就是這樣!我們的課程(甚至兩個!)成功地履行了它的功能:)如果你有時間和願望,你可以讓它多樣化一點。例如,確保計算器支援所有四種標準運算,並且不是數字,而是物件作為參數傳遞。作為附加材料,您可以在此處查看文章和範例: ServerMainmain()ClientMainCalculationInstance(int x, int y) 下一堂課見!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION