RPC編程

1 簡介

任何 RPC 客戶機-服務器程序的重要實體都包括 IDL 文件(接口定義文件)、客戶機 stub、服務器 stub 以及由客戶機和服務器程序共用的頭文件。客戶機和服務器 stub 使用 RPC 運行時庫通訊。RPC 運行時庫提供一套標準的運行時例程來支持 RPC 應用程序。瞭解運行時例程的內部狀況有助於進一步瞭解 RPC 編程。 數據庫

在通常的應用程序中,被調用的過程在相同的地址空間中運行,並把結果返回給發出調用的過程。在分佈式環境中,客戶機和服務器在不一樣的機器上運行,客戶端調用在服務器端運行的過程,並把結果發送回客戶機。這稱爲遠程過程調用 (RPC),是 RPC 編程的基礎。 編程

使用 RPC 編程是在分佈式環境中運行的客戶機和服務器應用程序之間進行可靠通訊的最強大、最高效的方法之一。 數組

圖 1. 基本的 RPC 客戶機-服務器交互
RPC 客戶機交互方式

圖 1 說明客戶機和服務器經過網絡完成 RPC 調用的方式。 緩存

當客戶機應用程序發出遠程過程調用時,在兩端的 RPC 運行時庫的幫助下,客戶機 stub 把與這個調用相關的信息經過網絡傳遞給服務器 stub,見 圖 1。服務器 stub 把所需的信息提供給服務器應用程序。服務器應用程序執行遠程過程調用,而後使用 RPC 運行時庫經過服務器 stub 把結果傳遞給客戶機 stub。最後,客戶機 stub 把結果返回給客戶機應用程序。stub 做爲應用程序和 RPC 運行時之間的接口,以二者能夠理解的格式交換信息。 服務器

在開發客戶機-服務器應用程序時,客戶機和服務器首先應該就要交換的過程的聲明和定義達成一致。這就是接口起的做用,接口維護客戶機和服務器都承認的全部過程聲明和數據類型。 網絡

咱們把全部共用的聲明和數據類型放在接口定義語言 (IDL) 文件中,客戶機和服務器將共享這個文件。咱們在 IDL 文件中使用 UUID,以使之在網絡上全部其餘接口中保持唯一。UUID 是一個唯一的隨機數,是由 uuidgen 實用程序使用網絡地址信息和系統時間生成的。 數據結構

圖 2 說明在開發簡單的客戶機-服務器分佈式應用程序時涉及的步驟。 併發

圖 2. 開發 RPC 客戶機-服務器應用程序
開發簡單應用程序涉及的步驟

用 IDL 編譯器編譯 IDL 文件,生成客戶機和服務器 stub 對象文件以及頭文件。這個頭文件包含共用的定義和過程。stub 文件在遠程過程調用期間做爲應用程序和 RPC 運行時庫之間的接口。頭文件包含在客戶機和服務器源代碼文件中。用 C 編譯器分別編譯客戶機和服務器文件,生成對象文件。客戶機對象文件和客戶機 stub 文件與 RPC 運行時庫連接,生成客戶機可執行程序。以類似的方式生成服務器可執行程序,見圖 2。 composer

本文中的經常使用術語

  • 綁定信息:

    它包含客戶機和服務器之間使用的通訊協議、服務器網絡地址和運行服務器進程的端點(端口號)的相關信息。 tcp

  • 綁定向量:

    綁定向量是一組引用綁定信息的綁定句柄。

  • 對象 UUID:

    除了管理接口的詳細信息以外,服務器應用程序還能夠管理對象 UUID 引用的資源。與接口同樣,服務器也能夠公佈對象 UUID。客戶機應用程序能夠只導入對象 UUID。

  • 入口點向量:

    RPC 運行時維護一個協議 ID 表以支持與協議相關的開關。它還提供一套與協議的調用、綁定、管理和連網方面相關的協議服務。每一個服務表示爲一個入口點。在每一個入口點中,有一套可使用的函數。

  • 塔:

    這是在名稱服務數據庫中存儲綁定信息的形式。

  • 協議序列:

    協議序列表明 RPC 通訊使用的網絡協議。最經常使用的協議序列是 ncacn_ip_tcp 和 ncadg_ip_udp。

    能夠看到,每一個協議序列中使用三個協議:

    • NCACN/NCADG – 描述鏈接 (CN) / 無鏈接 (DG) 協議的網絡通訊體系結構
    • IP – 描述地址
    • TCP/UDP – 傳輸層協議

幕後發生的狀況

圖 3 說明在客戶機和服務器之間完成 RPC 涉及的步驟。

圖 3. 在客戶機和服務器之間完成 RPC 涉及的步驟
完成 RPC 涉及的步驟
  1. 服務器 RPC 應用程序初始化期間它會向 RPC 運行時庫註冊接口。須要註冊接口是由於,客戶機在向服務器發出遠程過程調用時,要檢查它是否與服務器兼容。服務器建立綁定信息並把信息存儲在名稱服務數據庫中,客戶機能夠訪問這個數據庫並尋找到服務器的鏈接信息。服務器若是使用動態端點,那麼它把端點信息放在服務器系統上的本地端點映射數據庫中。本地端點映射數據庫用於存儲在此主機上運行的 RPC 服務器進程的全部端點。服務器啓動,監聽來自客戶機的遠程過程調用。
  2. 客戶機發出遠程過程調用,此時它會聯繫名稱服務數據庫,以尋找服務器系統的相關信息。RPC 運行時庫使用這些信息聯繫服務器系統上的本地端點映射數據庫,瞭解服務器進程在哪一個端點上監聽到達的 RPC。
  3. 客戶機找到服務器以後,客戶機 stub 把遠程過程調用和參數轉換爲服務器 stub 能夠理解的格式,而後交給客戶機運行時,由客戶機運行時經過網絡傳輸這些信息。
  4. 服務器 RPC 運行時庫接收到達的 RPC 調用,把它傳遞給服務器 stub,服務器 stub 把它轉換爲服務器能夠理解的格式。
  5. 執行 RPC 調用以後,服務器 stub 和服務器運行時把結果發送回客戶機。
  6. 客戶機 RPC 運行時接收執行結果,傳遞給客戶機 stub,客戶機 stub 再把它傳遞給客戶機進程。客戶機應用程序從客戶機 stub 接收結果並完成 RPC 調用。

本文的其他部分解釋完成遠程過程調用在客戶端和服務器端上須要使用的例程。

回頁首

2 服務器端運行時例程類別

1 在服務器上管理接口

本節概述在服務器應用程序中向 RPC 運行時註冊接口規範和取消註冊的例程。rpc_server_register_if 例程用於註冊接口,rpc_server_unregister_if 用於取消註冊。

  • rpc_server_register_if

     圖 3 所示,RPC 服務器應用程序必須執行的第一步是向運行時註冊它的接口。這個例程用於完成這個步驟,這須要提供 IDL 編譯器生成的接口句柄、類型 UUID 和管理器例程的入口點向量。

    原型和 I/O 參數以下:

    void rpc_server_register_if(IN rpc_if_handle_t  if_spec, 
    IN uuid_p_t mgr_type_uuid, IN rpc_mgr_epv_t  mgr_epv, OUT	
    unsigned32 *status);

    這個例程首先檢查傳遞的管理器入口點向量 mgr_epv 是不是 NULL。若是是 NULL,它就使用接口規範中提供的默認向量。接下來,它計算接口 uuid 的散列值,檢查 uuid 的格式是否有效。而後,得到一個鎖,以便在訪問接口註冊表以前保護它。它在接口註冊表中執行散列查詢,尋找請求的接口規範。若是查詢失敗,就建立一個新的接口條目並添加到註冊表中。把 mgr_epv 和 type_uuid 放在一個結構中,把這個結構的引用插入請求的接口的鏈表。如今,這個接口已經註冊了。

    rpc_server_unregister_if 例程用於從接口註冊表中刪除接口。

2 在服務器上管理協議序列

  • rpc_server_use_protseq

    經過調用這個例程,讓 RPC 運行時使用指定的協議序列。它爲所需的 Network Address Family (NAF) 建立描述符,並把它添加到正在監聽的服務器描述符池中。它使用一個動態分配的名稱做爲 Network Address Family Service 的描述符。

    原型和 I/O 參數以下:

    void rpc_server_use_protseq (IN unsigned_char_p_tprotseq, IN unsigned32
        max_call_requests,OUT unsigned32 *status);

    這個例程中的 Max_calls 輸入參數表示對於特定的協議序列所容許的最大併發調用數量。這個例程用 NULL 值表示端點來調用 rpc_server_protseq_ep 例程,這會搜索 RPC 協議 ID 序列表,返回給定的 RPC 協議序列字符串的協議 ID。若是在表中沒有找到這個協議序列,這個例程返回錯誤。接下來,用協議序列 ID、端點和 NAF ID 建立套接字描述符,並把它添加到正在監聽的描述符池中。

  • rpc_server_use_all_protseqs

    這個例程讓 RPC 運行時在運行時和操做系統支持的全部 RPC 協議序列上監聽 RPC。對於支持的每一個協議序列,這個例程調用rpc_server_use_protseq 建立套接字描述符,並把它添加到正在監聽的描述符池中。

    原型和 I/O 參數以下:

    void rpc_server_use_all_protseqs(IN  unsigned32 max_call_requests, OUT unsigned32
        *status);

    這個例程首先經過調用 rpc_network_inq_protseqs 得到運行時支持的有效協議序列的向量。對於支持的每一個協議序列,這個例程調用rpc_server_use_protseq 建立服務器套接字描述符,並把它添加到正在監聽的描述符池中。更多信息請參見 rpc_server_use_protseq。

    下面是用於管理協議序列的其餘重要例程:

    • rpc_server_use_all_protseq_if:這個例程讓 RPC 運行時監聽全部支持的協議序列。對於每一個支持的協議序列,它檢查指定的接口規範是否具備已知的端點。若是有,就經過調用 rpc_server_use_protseq_ep 根據這個端點建立套接字。
    • rpc_server_use_protseq_if:這個例程與 rpc_server_use_protseq 類似,可是它要查詢給定接口規範的端點並據此建立套接字。

3 管理綁定句柄

  • rpc_server_inq_bindings

    經過調用這個例程得到服務器綁定句柄的向量,這些句柄引用這個服務器的全部綁定信息。一組服務器綁定句柄稱爲向量。能夠對這些句柄發出 RPC 調用。注意,這些綁定不包含對象 UUID。

    原型和 I/O 參數以下:

    void rpc_server_inq_bindings(OUT rpc_binding_vector_t 
    **binding_vector (OUT unsigned32 *status);

    這個例程得到一組服務器綁定句柄。綁定句柄是在服務器應用程序調用管理協議序列中提到的任何例程時建立的。返回的綁定向量可能包含具備已知端點或動態端點的句柄。返回的端點類型取決於服務器應用程序在管理協議序列時調用的例程。若是沒有綁定句柄,這個例程返回rpc_s_no_bindings 並在 binding_vector 參數中返回 NULL。

4 把服務器導出到名稱服務

  • rpc_ns_binding_export

    通常狀況下,服務器會在名稱服務數據庫中公開地列出它的接口和對象 UUID,讓任何客戶機應用程序均可以使用此信息聯繫它。使用rpc_ns_binding_export 調用把此信息導出到數據庫。服務器不必定非要把此信息導出到數據庫;若是不導出,那麼只有已經知道服務器綁定的客戶機才能鏈接它。

    原型和 I/O 參數以下:

    void rpc_ns_binding_export(IN unsigned32 entry_name_syntax,IN unsigned_char_p_t
    entry_name, IN rpc_if_handle_t if_spec, IN rpc_binding_vector_p_t binding_vector,IN
    uuid_vector_p_t  object_uuid_vector, OUT unsigned32  *status);

    這個例程使用服務器的多個綁定句柄或對象 UUID 創建一個名稱服務數據庫條目。這個例程首先檢查 if_spec 或 binding_vec 是否爲 NULL,以及 object_uuid_vec 是否爲 NULL。若是是,它返回 rpc_s_nothing_to_export。它還統計要從綁定向量導出的非 NULL 綁定和非 NULL UUID 的數量。而後,篩選掉綁定向量中全部重複的綁定。接下來,檢查條目名稱的語法是否正確,根據運行時表示建立這個條目名稱的名稱服務表示。而後,在名稱空間中建立名稱服務條目。檢查是否指定了接口,把每一個非 NULL 綁定轉換爲塔表示,最後導出。還會導出全部非 NULL 對象 UUID。

  • rpc_ns_binding_inq_entry_name

    這個例程用於根據給定的綁定句柄從名稱服務數據庫獲取名稱服務條目。

    原型和 I/O 參數以下:

    void rpc_ns_binding_inq_entry_name(IN rpc_binding_handle_t binding,
    IN	unsigned32 entry_name_syntax, OUT unsigned_char_p_t  *entry_name,
    OUT unsigned32  *status);

    這個例程檢查傳遞的綁定句柄在名稱服務數據庫中是否有相應的條目名稱。若是條目存在,它應該是名稱服務表示格式的。把它轉換爲運行時表示的條目名稱,而後返回給調用者。若是條目不存在,這個例程返回狀態碼 rpc_s_no_entry_name。

5 在服務器上管理端點

  • rpc_ep_register

    這個例程用於向本地端點映射數據庫註冊服務器的端點。只有在經過調用 rpc_server_use_protseq 或 rpc_server_use_all_protseq 例程使用動態端點時,才調用它,由於在服務器每次從新啓動時端點均可能會變。若是經過調用 rpc_server_use_protseq_ep 例程使用已知端點,服務器應用程序仍然須要註冊端點,由於客戶機須要知道這個已知端點。若是經過調用 rpc_server_use_protseq_if 或 rpc_server_use_all_protseqs_if 例程使用已知端點,就不須要調用這個例程,由於客戶機能夠經過接口規範得到端點值。

    原型和 I/O 參數以下:

    void rpc_ep_register(IN rpc_if_handle_t if_spec, IN rpc_binding_vector_p_t
        binding_vec, IN uuid_vector_p_t  object_uuid_vec, IN unsigned_char_p_t 
        annotation, OUT
        unsigned32 *status);

    這個例程首先檢查接口句柄是否爲 NULL。若是爲 NULL,它返回 rpc_s_no_interfaces 錯誤。若是綁定向量爲 NULL,或者向量中沒有綁定,那麼它返回 rpc_s_no_bindings。不然,它循環遍歷綁定向量數組,尋找非 NULL 的綁定句柄指針。若是全部句柄爲 NULL,它返回 rpc_s_no_bindings 錯誤。它還檢查綁定向量數組中是否有不包含端點的綁定句柄,若是找到這樣的句柄,它返回 rpc_s_invalid_binding 錯誤。找到包含端點的有效綁定句柄以後,它用本地端點映射器在數據庫中註冊這個端點。

6 監聽 RPC

  • rpc_server_listen

    這個例程用於讓服務器監聽到達的遠程過程調用。

    原型和 I/O 參數以下:

    void rpc_server_listen(IN	unsigned32 max_calls_exec, OUT unsigned32
    *status);

    這個例程首先檢查是否已經有監聽器,從而確保任什麼時候候只有一個監聽器。而後,檢查是否有任何服務器套接字描述符並把它們添加到監聽器中,讓它能夠開始選擇它們。接下來,啓動全部調用執行者線程來監聽到達的 RPC。調用執行者線程處理來自 RPC 運行時的 RPC。調用線程的數量取決於輸入參數 max_calls,這個參數指定服務器能夠處理的最大併發 RPC 調用數量。若是服務器收到的 RPC 超過這個最大數量,它會把多餘的 RPC 排隊,直到有空閒的調用執行者線程能夠執行 RPC。這個例程會一直監聽,直到通知它中止監聽。當客戶機應用程序或服務器的管理器調用 rpc_mgmt_stop_server_listening 例程時,中止監聽。若是在描述符表中沒有找到服務器套接字,這個例程返回 rpc_s_no_protseq_registered 錯誤。

回頁首

3 客戶端運行時例程

1 管理綁定句柄

綁定句柄是大多數 RPC 運行時例程的基本輸入參數。可使用綁定句柄完成不一樣的任務,管理這些句柄是必需的。能夠根據須要把它們轉換和組合爲字符串格式,解析它們以尋找特定的字段值,使用它們查詢對象的相關信息,使用它們得到完整的綁定,複製和釋放它們。

在這個類別中(對於客戶端),有兩個重要的例程:

rpc_binding_to_string_binding  rpc_ep_resolve_binding
  • rpc_binding_to_string_binding

    這個例程把綁定數據結構轉換爲可讀的字符串表示。字符串表示的格式一般是:

    <UUID><Protocol Sequence><Network Address><Endpoint><Network
    Options>

    一般,應用程序調用這個例程來了解特定 RPC 服務所用的協議、IP 地址和端口號。

    原型和 I/O 參數以下:

    void rpc_binding_to_string_binding (IN rpc_binding_handle_t binding_h,
    OUT    unsigned_char_p_t       *string_binding, OUT unsigned32 *status)

    這個例程的輸入是綁定句柄,綁定句柄指向包含綁定表示的數據結構。能夠經過特定的調用得到 UUID、RPC 地址、端點、網絡地址和選項。

    若是綁定表示不包含 RPC 地址,就須要使用綁定入口點並經過鏈接查詢相關聯的 RPC 地址。使用網絡地址入口點和 RPC 地址的引用獲取網絡地址、端點和網絡選項詳細信息。

    從協議序列表獲取協議序列。這個表包含 NAF 和 RPC 支持的協議的標識符。

    而後,把以上全部數據組合成一個字符串並返回給調用者。使用 rpc_string_binding_composeroutine 完成這一步。

    還有一個做用相反的例程,它把綁定的字符串表示轉換爲綁定句柄。

  • rpc_ep_resolve_binding

    這個例程用於解析一個部分綁定的綁定句柄。若是一個綁定句柄只有網絡地址部分,尚未得到端點,就稱之爲部分綁定的。RPC 守護進程維護一個端點映射,其中包含給定接口和對象 UUID 的端點信息。RPC 運行時與這個守護進程聯繫,獲取端點信息並返回給調用者。

    原型和 I/O 參數以下:

    >void rpc_ep_resolve_binding(IN rpc_binding_handle_t  binding_h, 
    IN   rpc_if_handle_t       if_spec_h, OUT unsigned32      *status);

    這個例程的核心部分判斷綁定句柄表示是否沒有端點。若是有端點,例程把 rpc_s_ok 狀態返回給調用者。查詢 RPC 守護進程,首先嚐試從給定的接口獲取一個端點。若是找到端點,就把端點附加到綁定和綁定向量入口點中,讓協議服務知道綁定信息的變化,並把端點返回給調用者。

    若是接口沒有端點,那麼發出 RPC 調用,聯繫接口中指定的地址上的端點數據庫。在聯繫數據庫以前,運行時確認通訊超時值沒有設置爲無限等待。若是是無限等待,那麼運行時把它設置爲最大超時值。這是由於運行時不須要一直嘗試訪問端點數據庫。另外,爲了實例化端點數據庫,它要確認對象 UUID 爲 NULL。有了鏈接端點數據庫所需的徹底綁定句柄以後,檢查接口的協議版本與服務器協議版本的兼容性。若是不兼容,RPC 守護進程不返回端點。

    與日常同樣,綁定向量入口點把綁定句柄的變化告知協議服務。如今,下一個任務是在端點數據庫中查找給定接口的全部兼容的塔。爲此,客戶機以映射塔的形式提供數據,映射塔做爲查詢鍵。映射塔是根據給定的接口規範構造的,主要包含接口 UUID、版本、協議序列、協議版本等等。以映射塔做爲鍵,搜索端點數據庫,得到全部兼容的塔的列表。而後,把一個隨機選擇的兼容的塔轉換爲 RPC 地址,從中提取出端點。把這個端點附加到接口的綁定句柄中並返回給調用者。

2 經過名稱服務尋找服務器

名稱服務數據庫是服務器位置信息的存儲庫,其中的信息表示爲綁定信息。客戶機應用程序一般使用名稱服務 RPC 例程:

  • 獲取數據庫的引用
  • 獲取兼容綁定的列表
  • 查找綁定
  • 選擇綁定
  • 把搜索和獲取標記爲已完成
  • rpc_ns_binding_import_begin

    一般,RPC 服務器應用程序會公佈或導出它的位置,位置信息以綁定信息的形式存儲在名稱服務數據庫中。客戶機經過這個數據庫瞭解服務器的位置。客戶機應用程序使用 rpc_ns_binding_import_begin 例程獲取數據庫的引用,這個引用用於在名稱服務數據庫中搜索綁定信息。

    原型和 I/O 參數以下:

    void rpc_ns_binding_import_begin (IN unsigned32	entry_name_syntax
    IN	unsigned_char_p_t	entry_name, IN rpc_if_handle_t  if_spec,
    IN	uuid_p_t object_uuid, OUT	rpc_ns_handle_t  *import_context,
    OUT unsigned32	*status);

    第一個參數 entry_name_syntax 是一個整數值,它指定輸入 entry_name 的方式。entry_name 是搜索字符串的名稱。還能夠指定接口的句柄和對象 UUID。

    這個例程調用 rpc_ns_binding_lookup_begin,它執行所需的初始化。調用一個宏檢查傳遞的條目名稱語法和條目名稱是否爲 NULL。若是是,就使用默認值。

    爲名稱服務條目表示結構分配內存,其中包含條目名稱和語法。而後,把條目名稱展開成完整的 DNS 名稱並返回。而後初始化一個查找數據結構,這是一個鏈表。這個結構中的重要字段包括接口規範名稱服務緩存過時時間,這用於確認是否必須刷新緩存。而後建立並初始化一個查找節點,它也有名稱服務條目。把這個節點添加到查找列表的開頭,做爲導入上下文返回節點的引用。如今,客戶機應用程序可使用這個導入上下文從名稱服務數據庫獲取綁定信息。

  • rpc_ns_binding_import_next

    以 import_context 的形式得到查找結構的引用以後,客戶機應用程序可使用這個例程獲取給定接口的兼容綁定信息。還可使用對象 UUID。

    原型和 I/O 參數以下:

    void rpc_ns_binding_import_next ( [in] rpc_ns_handle_t  import_context,    
    [out] rpc_binding_handle_t *binding,  [out] unsigned32	*status);

    第一個任務是查找給定的名稱空間條目的兼容綁定。爲此,須要得到包含全部兼容綁定的綁定向量。這要調用 rpc_ns_binding_lookup_next 例程。在這個例程中,首先檢查是否有非空的上下文句柄。上下文句柄是用於在名稱服務數據庫中執行查找的引用。而後爲綁定向量分配內存並初始化。而後進入一個循環,獲取第一個節點並嘗試解析這個節點。解析是指得到兼容綁定的完整列表,或者在節點列表中添加有效的成員。解析的類型取決於名稱空間條目的類型。在這裏,類型能夠是搜索兼容的綁定,或者搜索由必須添加的組概要條目組成的上下文。名稱服務數據庫中的綁定信息存儲在稱爲塔的數據結構中。

    圖 4. 簡單的塔表示
    圖 4. 簡單的塔表示

    若是塔的協議序列、接口 id、傳輸語法和協議版本號與客戶機的接口匹配,就找到了兼容的綁定。在 rpc_ns_binding_import_next 中,根據解析後返回的狀態碼處理不一樣的狀況。若是綁定向量滿了,或者已經搜索了全部節點,那麼 rpc_ns_binding_lookup_next 例程返回。當綁定向量達到一個預約義的值時,就認爲它已經滿了。從 rpc_ns_binding_lookup_next 返回以後,執行選擇調用,從向量中隨機選擇一個兼容的綁定並返回給調用者。

3 管理接口信息

客戶機應用程序使用 RPC 運行時提供的如下例程查詢接口的詳細信息:

  • rpc_if_inq_id

    這個例程查詢接口的標識符和接口 UUID 的主版本或次版本。須要這些數據的狀況包括對比接口和塔標識符、從名稱服務數據庫中刪除多個綁定等等。

    原型和 I/O 參數以下:

    void rpc_if_inq_id(IN rpc_if_handle_t  if_spec, OUT rpc_if_id_t
    *if_id, OUT unsigned32 *status);

    過程很簡單:它從接口表示結構 (if_spec) 獲取接口的 UUID 和版本,而後把這些數據放進接口標識符結構中 (if_id)。這個結構的字段是接口的 UUID、主版本和次版本。從 if_spec 得到的版本號是一個 32 位的值,將之與 0xffff 進行 AND 計算能夠獲得主版本,右移 16 次能夠獲得次版本。把這些數據放進 if_id 中並把它的引用返回給調用者。

  • rpc_if_id_vector_free

    應用程序的退出處理函數或清理例程能夠調用這個例程。

    原型和 I/O 參數以下:

    void rpc_if_id_vector_free (IN/OUT rpc_if_id_vector_p_t  *if_id_vector,
    >OUT unsigned32  *status);

    這個簡單的例程釋放運行時分配給接口 ID 向量結構的內存。這個結構包含接口 ID 結構的指針和接口的數量。若是輸入向量自己爲空,那麼返回 rpc_s_invalid_arg 狀態。不然,循環遍歷向量,釋放每一個接口的內存。最後,還要釋放分配給向量的內存並把 NULL 向量返回給調用者。

4 查詢協議序列

  • rpc_network_inq_protseqs

    瞭解給定主機上支持的全部協議序列有助於作出應用程序和運行時級的決策。例如,RPC 運行時應該只監聽主機支持的有效協議序列。RPC 應用程序只需查詢主機支持的協議序列。在這種狀況下,須要調用這個例程。

    原型和 I/O 參數以下:

    void rpc_network_inq_protseqs(OUT rpc_protseq_vector_p_t *protseq_vector, 
    OUT unsigned32	*status)

    首先檢查協議序列的數量是否爲零。若是爲零,這個例程返回並指出沒有協議序列。不然,爲保存協議序列字符串分配所需的內存。而後遍歷協議序列 ID 表,把協議字符串複製到輸出參數 ‘protseq_vector’ 中。

  • rpc_network_is_protseq_valid

    在使用協議以前,RPC 應用程序可能但願確認主機上是否支持給定的協議序列。在這種狀況下,以協議序列字符串做爲輸入調用 rpc_network_is_protseq_valid。常常在調用 rpc_server_use_protseq 以前調用這個例程。

    原型和 I/O 參數以下:

    boolean rpc_network_is_protseq_valid( IN unsigned_char_p_t	protseq, 
    OUT unsigned32 *status)

    這個例程在協議序列 ID 表中搜索給定的輸入字符串。若是沒有找到,就返回 rpc_s_protseq_not_supported。協議序列 ID 表包含一個布爾字段,表示是否支持給定的協議序列。在運行時初始化期間填充這個字段。這個例程遍歷這個表,獲取網絡地址系列、接口和協議。這三個參數用於在操做系統上打開套接字,若是成功,就意味着協議支持字段被設置爲 TRUE。

    把相同的值返回給 rpc_network_is_protseq_valid() 的調用者。若是返回值爲 FALSE,那麼 status 字段設置爲 rpc_s_protseq_not_supported。若是沒有找到與給定的協議序列字符串匹配的協議序列,那麼 status 字段被設置爲 rpc_s_invalid_rpc_protseq。

回頁首

4 共用的例程

管理端點映射

  • rpc_mgmt_ep_elt_inq_begin

    RPC 應用程序要查看端點的內容時,它首先必須得到訪問端點所需的引用。在這種狀況下,調用這個例程。

    原型和 I/O 參數以下:

    void rpc_mgmt_ep_elt_inq_begin (IN rpc_binding_handle_t input_binding,
    IN	unsigned32 inquiry_type, IN rpc_if_id_p_t if_id, IN unsigned32 vers_option, 
    IN	uuid_p_t object_uuid,OUT rpc_ep_inq_handle_t *inquiry_context,
    OUT unsigned32	*status);

    這個例程建立一個查詢上下文,以用來訪問本地或遠程端點。爲了得到這個上下文,首先須要綁定由輸入綁定參數指定的本地或遠程主機上的端點。若是傳遞的參數是 NULL,那麼運行時嘗試綁定包含支持的協議序列之一的本地端點。在此以後,把字符串綁定轉換爲綁定句柄。若是輸入綁定參數不是 NULL,就意味着端點在遠程主機上。從這個輸入綁定句柄獲取 RPC 地址和綁定數據結構的其餘字段值,好比協議版本、超時等,把它們複製到另外一個句柄表示中。rpc_binding_copy 例程完成這個任務。這裏的目標只是獲取端點數據庫的引用。所以,從 rpc_binding_copy 得到新的句柄以後,清除與 RPC 地址相關聯的端點。把獲取的句柄複製到端點查詢上下文結構的適當字段中。這個結構還有其餘字段,好比查詢類型、對象 UUID、接口 ID 等等。適當地填充全部結構字段並把這個結構的引用做爲 inquiry_context 返回給調用者。

  • rpc_mgmt_ep_elt_inq_next

    調用這個例程查看端點數據庫的內容。通常狀況下,端點數據庫的內容包括 UUID、接口 ID、註解表示和字符串綁定信息。

    原型和 I/O 參數以下:

    void rpc_mgmt_ep_elt_inq_next (IN    rpc_ep_inq_handle_t  inquiry_context,
    OUT  rpc_if_id_t *if_id, OUT rpc_binding_handle_t *binding,
    OUT  uuid_t *object_uuid, OUT unsigned_char_p_t  *annotation,
    OUT  unsigned32 *status);

    使用從 rpc_mgmt_ep_elt_inq_begin 例程得到的查詢上下文引用訪問端點數據庫。與名稱服務數據庫同樣,信息在端點數據庫中存儲爲塔的形式。把獲取的每一個塔表示轉換爲綁定表示。若是轉換成功,就從查詢上下文引用獲取接口 ID、對象 UUID 和註解等其餘數據。在一個循環中進行這個處理,直到端點數據庫中沒有元素爲止。

  • rpc_mgmt_ep_unregister

    當服務器再也不但願在端點中註冊時,調用這個例程。而後,服務器的位置信息會從端點數據庫中刪除掉。

    原型和 I/O 參數以下:

    void rpc_mgmt_ep_unregister(IN  rpc_binding_handle_t ep_binding, 
    IN rpc_if_id_p_t  if_id, IN rpc_binding_handle_t binding,
    IN	uuid_p_t object_uuid, OUT unsigned32 *status);

    能夠對指定的接口、綁定句柄列表(每一個支持的協議一個句柄)和指定的對象 UUID 列表執行取消註冊。檢查全部輸入參數以後,獲取訪問端點數據庫的引用。對於輸入列表中指定的每一個綁定,獲取塔的引用列表,用於訪問塔表示。另外,對於輸入列表中指定的每一個對象 UUID,執行從端點中刪除它們的命令。而後釋放塔,再釋放塔的引用。繼續處理,直到刪除輸入列表中指定的全部綁定爲止。

管理本地或遠程應用程序

全部管理例程都用於瞭解服務器的監聽狀態、服務器的統計數據、註冊的接口列表等等。根據綁定句柄在本地或遠程執行這個調用。NULL 綁定句柄表示在本地執行調用。

  • rpc_mgmt_is_server_listening

    應用程序有時候但願確認某個服務器是否正在監聽。把綁定句柄做爲輸入傳遞給這個例程,就能夠查明監聽狀態。true 值表示服務器正在監聽到達的請求。

    原型和 I/O 參數以下:

    boolean32 rpc_mgmt_is_server_listening(IN rpc_binding_handle_t binding_handle,  OUT 
    unsigned32 	*status);

    正如剛纔提到的,NULL 綁定句柄表示在本地主機上執行這個調用。不然,先檢查綁定句柄是否能夠遠程使用,而後在遠程主機上執行調用。每一個正在進行監聽的服務器維護一個標誌,若是在註冊的端口上有正在監聽的套接字,這個標誌就設置爲 true。若是運行時沒法激活監聽套接字,這個標誌就設置爲 false。

    執行查詢時,把這個標誌的值返回給進行調用的應用程序。應用程序能夠經過調用 rpc_mgmt_stop_server_listening 要求服務器中止監聽。完成全部未處理或正在處理的請求以後,服務器中止監聽,再也不接受任何新的請求。

  • rpc_mgmt_inq_stats

    有時候,須要檢查接口,確認它工做正常。在這種狀況下,獲取統計數據有助於調試,好比接口發送或接收的數據包數量和發送或接收的 RPC 調用數量。

    原型和 I/O 參數以下:

    void rpc_mgmt_inq_stats(IN rpc_binding_handle_t binding_handle, OUT
    rpc_stats_vector_p_t *statistics, OUT unsigned32 *status);

    這個例程獲取前面提到的統計數據。使用管理入口點向量查詢協議服務,獲取系統上支持的每一個協議的統計數據。

管理名稱服務的元素

這包括管理名稱服務條目、組和概要。

  • rpc_ns_mgmt_entry_create

    對名稱服務數據庫有適當訪問權的應用程序能夠建立名稱並存儲在數據庫中。其餘應用程序能夠根據須要訪問這個名稱。

    原型和 I/O 參數以下:

    void rpc_ns_mgmt_entry_create(IN unsigned32  entry_name_syntax, IN 
    unsigned_char_p_t entry_name,OUT unsigned32  *status);

    首先,必須從給定的條目名稱獲取名稱服務條目表示的引用。這個表示是一個結構,包含名稱和名稱長度字段。經過展開給定的條目名稱並獲取完整的名稱和長度,得到引用。這須要解析條目名稱並把它轉換爲兼容的格式。使用這個引用在名稱服務數據庫中建立條目。

  • rpc_ns_mgmt_entry_create

    這個例程在名稱服務數據庫中建立服務器條目。服務器條目包含接口標識符、綁定信息和可選的對象 UUID。接口標識符包含接口 UUID 和它的版本號。客戶機使用這個標識符查找合適的接口。

    原型和 I/O 參數以下:

    void rpc_ns_mgmt_entry_create(IN unsigned32 entry_name_syntax, IN 
    unsigned_char_p_t entry_name, OUT unsigned32 *status);

    entry_name_syntax 是一個整數值,它指定條目名稱的語法。若是傳遞 NULL,就使用默認的條目語法。這個例程解析條目使用的語法,而後把傳遞的條目轉換爲名稱服務表示。最後,在名稱服務數據庫中建立相關的條目,例程返回。

  • rpc_ns_group_mbr_add

    RPC 運行時爲元素、組、概要和塔提供查詢例程,這經過查詢或訪問名稱服務數據庫來完成。

    使用這個例程在組條目中添加成員。組條目是一種名稱服務條目,其中包含提供相同接口的服務器條目(成員)。客戶機搜索組中提供相同接口的全部成員,尋找合適的服務器。

    原型和 I/O 參數以下:

    oid rpc_ns_group_mbr_add(IN unsigned32 group_name_syntax, IN 
    unsigned_char_p_t	group_name, IN unsigned32 member_name_syntax,
    IN unsigned_char_p_t	member_name,OUT	unsigned32 *status);

    這個例程的輸入參數包括 group_name_syntax 和 member_name_syntax,它們是指定組和成員語法的整數值。若是傳遞的值是 NULL,就使用默認語法。group_name 和 member_name 分別是採用人可讀的格式的組名和成員名。

    這個例程首先把組名語法轉換爲內部形式,而後把組名轉換爲名稱服務表示。一樣,把成員名語法轉換爲內部形式,把成員名轉換爲名稱服務表示。它在名稱服務數據庫中搜索這個組名,若是沒有找到,就建立組條目,而後在剛建立的組中添加成員條目。若是找到了組條目,這個例程就只需在指定的組中添加成員條目。

  • rpc_ns_group_mbr_inq_begin

    這個例程開始一個查詢上下文,用於向調用者返回組成員。查詢上下文只是一個結構的指針,在內部維護這個結構,用於查詢組成員、概要、塔或 uuid 成員。

    原型和 I/O 參數以下:

    void rpc_ns_group_mbr_inq_begin(IN unsigned32 group_name_syntax, 
    IN unsigned_char_p_t group_name, IN unsigned32 member_name_syntax,
    OUT rpc_ns_handle_t *inquiry_context, OUT unsigned32 *status);

    這個例程首先把組名語法轉換爲內部形式,把人可讀的組名轉換爲名稱服務表示。接下來,把成員名語法轉換爲內部形式。最後,爲組成員建立查詢上下文,設置查詢上下文結構中的成員名語法字段,把建立的查詢上下文結構的指針返回給調用者。而後,能夠把查詢上下文指針/句柄傳遞給 rpc_ns_group_mbr_inq_next 例程,這個例程返回組中的成員。

  • rpc_ns_group_mbr_inq_next

    在調用 rpc_ns_group_mbr_inq_begin 以後,使用這個例程獲取特定組的成員。

    原型和 I/O 參數以下:

    void rpc_ns_group_mbr_inq_next(IN rpc_ns_handle_t inquiry_context,
    OUT unsigned_char_p_t	*member_name, OUT unsigned32 *status);

    這個例程以 rpc_ns_group_mbr_inq_begin 返回的查詢上下文句柄做爲輸入。它首先檢查傳遞的查詢上下文是否非 NULL,以及是不是組成員的上下文。若是傳遞的查詢上下文是 NULL,或者不是用於組成員查詢的上下文,它返回 rpc_s_invalid_ns_handle。不然,讀取組的成員,把成員名由名稱服務格式轉換爲人可讀的格式並返回給調用者。

  • rpc_ns_group_mbr_inq_done

    經過調用這個例程,結束之前調用 rpc_ns_group_mbr_inq_begin 所設置的查詢上下文。

    原型和 I/O 參數以下:

    void rpc_ns_group_mbr_inq_done (IN, OUT rpc_ns_handle_t *inquiry_context,
    OUT unsigned32 *status);

    這個例程首先檢查傳遞的查詢上下文是否非 NULL,以及是不是用於組成員查詢的上下文。若是是 NULL 或者不是用於組成員查詢的上下文,它返回 rpc_s_invalid_ns_handle。不然,它釋放在 rpc_ns_group_mbr_inq_begin 中分配給查詢上下文結構的內存。

回頁首

5 結束語

在本文中,咱們討論了任何 RPC 客戶機和服務器應用程序調用的最基本、最重要的例程。還解釋了 RPC 運行時如何實現每一個例程的功能。咱們但願本文能夠幫助讀者更深刻地瞭解 RPC 運行時的工做原理。

相關文章
相關標籤/搜索