什麼是遠端過程呼叫(RCP),遠端過程呼叫服務實現原理詳解

2020-07-16 10:04:38
遠端過程呼叫,簡稱 RPC,是一種最為常見的遠端服務。RPC 對於通過網路連線系統之間的過程呼叫進行了抽象。它在許多方面都類似於 IPC 機制,並且通常建立在 IPC 之上。不過,因為現在的情況是進程處在不同系統上,所以應提供基於訊息的通訊方案,以提供遠端服務。

與 IPC 的訊息不一樣,RPC 通訊交換的訊息具有明確結構,不再僅僅是封包。訊息傳到 RPC 服務,RPC 服務監聽遠端系統的埠號;訊息包含用於指定執行函數的一個識別符號以及傳遞給函數的一些引數。然後,函數按要求來執行,而所有結果會通過另一訊息,傳遞回到請求者。

只是一個數位,處於訊息分組頭部。雖然每個系統通常只有一個網路地址,但是對於這個地址它有許多埠號,以便區分所支援的多個網路服務。如果一個遠端進程需要服務,那麼它向適當埠傳送訊息。

例如,如果有個系統允許其他系統列出當前使用者,那麼它可以有一個支援這個的 RPC 服務,該服務會監聽某個埠,如 3027。任何一個遠端系統如要得到所需資訊(即列出當前使用者),只要向伺服器埠 3027 傳送一個 RPC 訊息,就能通過回復訊息收到資料。

RPC 語意允許客戶呼叫位於遠端主機的過程,就如呼叫本地過程一樣。通過用戶端提供的存根,RPC 系統隱藏通訊細節。

通常,對於每個單獨遠端過程,都有一個存根。當客戶呼叫遠端過程時,RPC 系統呼叫適當存根,並且傳遞遠端過程引數。這個存根定位伺服器的埠,並且封裝引數(打包引數),以便通過網路傳輸。然後,存根通過訊息傳遞,向伺服器傳送一個訊息。

伺服器的類似存根收到這個訊息,並且呼叫伺服器的過程。如果必要,返回值可通過同樣技術傳回到客戶機。對於 Windows 系統,編譯由 MIDL 語言編寫的規範,可以生成存根程式碼。Microsoft 介面定義語言用於定義客戶機與伺服器之間的介面。

有一個必須處理的事項,涉及如何處理客戶機和伺服器系統的不同資料表示。考慮 32 位整數的表示。有的系統使用記憶體的高地址,以儲存高位位元組(稱為大端結尾),而其他系統使用記憶體的高地址,以儲存低位位元組(稱為小端結尾)。沒有哪種順序“更好”;這是由電腦架構來選擇的。

為了解決這一差異,許多 RPC 系統定義一個獨立於機器的資料表示。一種這樣的表示稱為外部資料表示(簡稱XDR)。在用戶端,引數封裝將機器相關資料打包成 XDR,再傳送到伺服器。在伺服器端,XDR 資料被分封,再轉成機器相關資料以交給伺服器。

另外一個重要事項涉及呼叫語意。雖然本地過程呼叫只在極端情況下才失敗,但是由於常見網路錯誤,RPC 可能執行失敗或者多次重複執行。解決這個問題的一種方法是:作業系統確保每個訊息執行正好一次,而非執行最多一次。大多數本地過程呼叫具有“正好一次”的特點,但是實現更難。

首先,考慮“最多一次”,可以通過為每個訊息附加時間戳來實現。伺服器對所處理的訊息應有一個完整的或足夠長的時間戳的歷史,以便確保能夠檢測到重複訊息。進來的訊息,如果其時間戳已出現過,則被忽略。這樣,客戶能夠一次或多次傳送訊息,並確保僅執行一次。

對於“正好一次”,需要消除伺服器從未收到請求的風險。為了做到這點,伺服器必須執行前面所述的“最多一次”的協定,但是也必須向客戶確認 RPC 呼叫已經收到並且已經執行。這些 ACK(確認)訊息在網路中是常見的。客戶機應週期性地重發每個 RPC 呼叫,直到它接收到對該呼叫的 ACK。

然而,另外一個重要問題涉及伺服器和客戶機之間的通訊。對於標準的過程呼叫,連結、載入或執行有一定形式的系結,以便過程名稱被過程的記憶體地址所替代。RPC 方案也要有一個類似於客戶機和伺服器埠之間的系結,但是客戶機如何知道伺服器上的埠呢?這兩個都沒有對方的完全資訊,因為它們並不共用記憶體。有兩種方法是常見的。

第一種方法,係結資訊可以按固定的埠地址形式預先固定。在編譯時,RPC 呼叫有一個與它關聯的固定埠。一旦程式編譯後,伺服器無法更改請求服務的埠號。

第二種方法,係結通過交會機制動態進行。通常,作業系統在一個固定 RPC 埠上,提供交會服務程式或月老。客戶程式傳送一個包括 RPC 名稱的訊息到交會服務程式,以便請求所需執行 RPC 的埠地址。在得到返回的埠號後,RPC 呼叫可以傳送到這一埠號,直到進程終止(或伺服器崩潰)。

這種方式的初始請求需要額外開銷,但是比第一種更靈活。圖 1 為這種互動的一個範例。

遠程過程調用(RPC)的執行
圖 1 遠端過程呼叫(RPC)的執行