?? rcp協議2.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0052)http://www.longen.org/L-R/detaill~r/RPCProtocol2.htm -->
<HTML><HEAD><TITLE>新建網頁 0</TITLE>
<META http-equiv=Content-Language content=zh-cn>
<META content="MSHTML 6.00.2800.1400" name=GENERATOR>
<META content=FrontPage.Editor.Document name=ProgId>
<META http-equiv=Content-Type content="text/html; charset=gb2312"></HEAD>
<BODY>
<TABLE id=AutoNumber1 cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD width="100%">
<H4>RCP協議2</H4>
<P>本文介紹用于ONC RPC協議規范。此協議使用XDR語言進行描述,并文不打算描述具體的使用細節而只介紹RPC協議本身。</P>
<P>ONC
RPC是基于RPC調用模型,此模型和本地過程調用(LPC)類似。對于LPC而言,調用方只需要將參加放入一些固定的地址,如寄存器,然后將程序的控制權轉交給另一個程序,最后再由那個程序返回即可。RCP與之類似,RCP在調用一個遠程過程后,自己進行等待狀態,傳往遠程過程的參數包括過程參數,返回參數包括執行結果。當收到包括執行結果的消息后,本地進程從消息中取得結果,調用進程重新開始執行。在服務器一方,有一個程序在等待調用,當有一個調用到達時,服務器進程取得進程參數,計算結果,然后返回結果。</P>
<P>在上面的模型中,在某一個時刻只有一個進程是活動的。ONC
RCP沒有規定如何處理并發。調用可以同步的也可以是異步的。服務器可以創建一個線程來接收用戶請求,也可以自己來接收用戶請求。下面是RCP不同于LPC的幾點:</P>
<P>1. 錯誤處理:對于遠程服務器和網絡失敗必須進行處理;<BR>2.
全局變量:因為遠程服務不可能訪問本地的變量,因此不能傳送全局變量;<BR>3. 性能:RPC通常比LPC要慢許多;<BR>4.
認證:因為RPC通常要經過網絡,因此必須進行認證。</P>
<P>雖然有現成的工具可以自動生成相關的服務器和客戶方,但是協議本身仍然需要仔細設計。</P>
<P>RPC可由不同的傳輸協議實現,但RPC依然需要獲得傳輸層的信息(這一過程本文不涉及)。這是因為有時候,傳輸層會限制信息的長度,同時通信雙方必須遵守同一個通信協議。RPC不會試圖實現任何可靠性,應用程序應該注意相關的可靠性問題。如果RPC在TCP上運行,一切好說。TCP代替應用程序做一些工作,但如果RPC運行在UDP上,應用程序必須注意超時,重傳,多次請求檢查等工作。因為傳輸是獨立的,因此RPC必須從相關的傳輸層上獲得是否正確執行的信息。對于UDP來講,如果應用程序沒有得到響應,它必須重新請求;重新請求后得到響應,應用程序只能推斷出服務器至少執行了一次請求。通過對請求加上編號,可以使得服務器不對重復的請求加以響應。因此我們可以確定在收到確定后,服務器至多執行了一次請求。這里需要注意的一點是:客戶的請求的ID號只能用于和服務器內的ID號進行相等比較,不能進行其它操作。
<BR>即使使用了TCP,在沒有得到響應時,我們也不能確定服務器是不是一定執行了相關的操作。我們還需要使用超時機制以保證服務器沒有失敗。RPC可以使用其它的協議,如VMTP。但本文中我們以TCP作為例子。RPC協議本身不包括綁定,這是由高層協議來完成的。RPC必須提供:</P>
<P>1. 被調用過程必須是唯一的;<BR>2. 必須提供調用消息和響應消息的配對機制;<BR>3. 必須提供認證機制;</P>
<P>除上面的要求外還必須提供對下面問題的檢測機制:</P>
<P>1. RPC不匹配;<BR>2. 版本號不匹配;<BR>3. 協議錯誤,如參數錯誤;<BR>4. 必須提供認證錯誤的原因;<BR>5.
提供其它錯誤信息。</P>
<P>RCP調用有三個無符號整數域:遠程程序號,程序版本號和遠程過程號。程序號必須統一管理 (<A
href="mailto:(rpc@sun.com">mailto:(rpc@sun.com</A>)
。在擁有一個程序號后,我們就可以實現自己的遠程程序了。第一個實現通常以版本1來標記,這個版本號用于標記我們應該使用何種版本的程序。過程號用于標記被調用的程序。RCP本身可以變化,RCP消息協議也可以變化。因此消息本身也有RPC版本號,它通常和這里描述的兩個版本號之一一致。返回消息必須提供信息以足以確定下面錯誤:</P>
<P>1. 遠程實現不支持版本2,返回可以支持的最高和最低版本號;<BR>2. 遠程程序在遠程機上不可用;<BR>3.
遠程程序不支持請求的版本號,返回支持的最高和最低版本號;<BR>4. 請求的過程不存在;<BR>5. 參數錯誤</P>
<P>認證機制要求請求消息有兩個認證域:證書和確認。響應消息有一個域:響應確認。RPC對這三個域統一定義如下:</P>
<P>enum auth_flavor {<BR>AUTH_NONE = 0,<BR>AUTH_SYS = 1,<BR>AUTH_SHORT =
2<BR>/* and more to be defined */<BR>};</P>
<P>struct opaque_auth {<BR>auth_flavor flavor;<BR>opaque
body<400>;<BR>};</P>
<P>對于認證結構語義的解釋不在本協議規定之列。如果認證失敗,必須提供失敗原因。程序號成組給出,下面是一些規定:</P>
<P>0 - 1fffffff 由rpc@sun.com定義<BR>20000000 - 3fffffff 用戶定義<BR>40000000 -
5fffffff 臨時<BR>60000000 - 7fffffff reserved<BR>80000000 - 9fffffff
reserved<BR>a0000000 - bfffffff reserved<BR>c0000000 - dfffffff
reserved<BR>e0000000 - ffffffff reserved</P>
<P>其中第一組中要求的號碼要求所有的RPC過程必須遵守,即同一個號必須提供相同的功能。第二組主要用于調試。第三組是由程序臨時產生的號碼。其它號碼保留,不得使用。用戶可以向服務器發送一組請求,稱為批處理。批處理時用戶不用等待服務器返回,而是使用一個特定的請求獲得這一組請求的響應。批處理時通常使用TCP。而UDP多使用于廣播式RPC,對于支持廣播的服務器,它們在成功時返回確定,在失敗時什么也不返回(此規定可根據實現不同而不用加以遵守)。下面我們來定義RPC消息:</P>
<P>enum msg_type {<BR>CALL = 0,<BR>REPLY = 1<BR>};</P>
<P>當一個消息接收到時,下面是調用遠程過程調用的狀態:</P>
<P>enum accept_stat {<BR>SUCCESS = 0, /* RPC executed successfully
*/<BR>PROG_UNAVAIL = 1, /* remote hasn't exported program
*/<BR>PROG_MISMATCH = 2, /* remote can't support version #
*/<BR>PROC_UNAVAIL = 3, /* program can't support procedure
*/<BR>GARBAGE_ARGS = 4, /* procedure can't decode params */<BR>SYSTEM_ERR
= 5 /* errors like memory allocation failure */<BR>};</P>
<P>調用消息被拒絕的原因如下:</P>
<P>enum reject_stat {<BR>RPC_MISMATCH = 0, /* RPC version number != 2
*/<BR>AUTH_ERROR = 1 /* remote can't authenticate caller */<BR>};</P>
<P>認證失敗的原因如下:</P>
<P>enum auth_stat {<BR>AUTH_OK = 0, /* success */<BR>/*<BR>* failed at
remote end<BR>*/<BR>AUTH_BADCRED = 1, /* bad credential (seal broken)
*/<BR>AUTH_REJECTEDCRED = 2, /* client must begin new session
*/<BR>AUTH_BADVERF = 3, /* bad verifier (seal broken)
*/<BR>AUTH_REJECTEDVERF = 4, /* verifier expired or replayed
*/<BR>AUTH_TOOWEAK = 5, /* rejected for security reasons */<BR>/*<BR>*
failed locally<BR>*/<BR>AUTH_INVALIDRESP = 6, /* bogus response verifier
*/<BR>AUTH_FAILED = 7 /* reason unknown */<BR>};</P>
<P>消息體格式如下,其中XID是消息號,請求消息和返回消息的消息號必須一致。</P>
<P>struct rpc_msg {<BR>unsigned int xid;<BR>union switch (msg_type mtype)
{<BR>case CALL:<BR>call_body cbody;<BR>case REPLY:<BR>reply_body
rbody;<BR>} body;<BR>};</P>
<P>RPC的消息體,版本號為2:</P>
<P>struct call_body {<BR>unsigned int rpcvers; /* must be equal to two (2)
*/<BR>unsigned int prog;<BR>unsigned int vers;<BR>unsigned int
proc;<BR>opaque_auth cred;<BR>opaque_auth verf;<BR>/* procedure specific
parameters start here */<BR>};</P>
<P>雖然cred和verf是兩個數據域,但我們通常將它們做一個處理。而響應消息格式如下:</P>
<P>union reply_body switch (reply_stat stat) {<BR>case
MSG_ACCEPTED:<BR>accepted_reply areply;<BR>case
MSG_DENIED:<BR>rejected_reply rreply;<BR>} reply;</P>
<P>如果服務器接收這個請求,必須返回一個認證域以使自己為客戶認證:</P>
<P>struct accepted_reply {<BR>opaque_auth verf;<BR>union switch
(accept_stat stat) {<BR>case SUCCESS:<BR>opaque results[0];<BR>/*<BR>*
procedure-specific results start here<BR>*/<BR>case
PROG_MISMATCH:<BR>struct {<BR>unsigned int low;<BR>unsigned int high;<BR>}
mismatch_info;<BR>default:<BR>/*<BR>* Void. Cases include PROG_UNAVAIL,
PROC_UNAVAIL,<BR>* GARBAGE_ARGS, and SYSTEM_ERR.<BR>*/<BR>void;<BR>}
reply_data;<BR>};</P>
<P>服務器可以因為版本原因或認證原因拒絕請求,下面是拒絕消息的格式:</P>
<P>union rejected_reply switch (reject_stat stat) {<BR>case
RPC_MISMATCH:<BR>struct {<BR>unsigned int low;<BR>unsigned int high;<BR>}
mismatch_info;<BR>case AUTH_ERROR:<BR>auth_stat stat;<BR>};</P>
<P>認證雖然對于RPC是透明的,可是RPC必須有兩種認證必須實現。任何一種新的認證機制必須有一種獨立的認證號,這個號是統一管理的,用戶可以通過
<A href="mailto:rcp@sun.com">rcp@sun.com</A>
獲得。其中NULL認證必須實現,我們推薦實現系統認證。NULL認證其實就是不認證,這里推薦相關的數據域長度為0。</P>
<P>RPC在其它通信協議之上,為了保證一個消息和另一消息分離并能夠從錯誤中進行恢復,我們規定了一個消息片斷稱為RM,一個消息在一個RM中。一個RM中可以有多個記錄片斷,每個片斷除四個字節的頭外,還有一個0到2的31次方減1的數據域。<BR>下面我們來描述一下RPC語言,這是對XDR的一個擴展。下面是一個PING的例子:</P>
<P>program PING_PROG {<BR>/*<BR>* Latest and greatest
version<BR>*/<BR>version PING_VERS_PINGBACK
{<BR>void<BR>PINGPROC_NULL(void) = 0;<BR>/*<BR>* Ping the client, return
the round-trip time<BR>* (in microseconds). Returns -1 if the
operation<BR>* timed out.<BR>*/<BR>int<BR>PINGPROC_PINGBACK(void) =
1;<BR>} = 2;<BR><BR>/*<BR>* Original version<BR>*/<BR>version
PING_VERS_ORIG {<BR>void<BR>PINGPROC_NULL(void) = 0;<BR>} = 1;<BR>} =
1;<BR><BR>const PING_VERS = 2; /* latest version */</P>
<P>上程序中包括了三個小程序。通過上面的例子,我們可以看出RPC語言和XDR語言很象,不過就加了一個program-def而已。</P>
<P>program-def: <BR>"program" identifier "{" <BR>version-def
<BR>version-def * <BR>"}" "=" constant ";" <BR>version-def: <BR>"version"
identifier "{" <BR>procedure-def <BR>procedure-def * <BR>"}" "=" constant
";" <BR>procedure-def: <BR>type-specifier identifier "(" type-specifier
<BR>("," type-specifier )* ")" "=" constant ";" </P>
<P>下面是一些基本的規定:</P>
<P>不使用program和version作為變量名;在一個域中版本名,過程名,版本號,過程號不能出現兩次;程序標記在一個域中是常量,只能使用未使用的常量可被指定到程序,版本和過程。最后我們來看看系統認證。如果要使用系統認證,它的標識為AUTH_SYS。證書由下面的結構表示:</P>
<P>struct authsys_parms {<BR>unsigned int stamp;<BR>string
machinename<255>;<BR>unsigned int uid;<BR>unsigned int
gid;<BR>unsigned int gids<16>;<BR>};</P>
<P>stamp是一個ID號由調用機產生。machinename是調用機的機器名,uid和gid是用戶ID和組ID,gids是包括此用戶的組的集合。一般verf指定為AUTH_NONE。這個證書只在一個特定的域內有效(此域是由機器名,用戶ID和組ID組成的)。</P>
<P>從服務器接收到的Verf的認證號可以是AUTH_NONE或AUTH_SHORT。在接收到后者時,返回的是一個新的認證結構。這個新的結構可以取代原來的AUTH_SYS結構而被傳送到服務器。這樣客戶可以傳送比較少的數據而獲得認證。服務器保留結構和舊結構的一個映射。當然,服務器可以隨時取消這種映射,此時客戶的請求會被拒絕。此時用戶可以必須使用原有的結構進行認證。這種認證本身并不能保證安全,真正的網絡安全必須通過別的方式進行保證。</P></TD></TR></TBODY></TABLE></BODY></HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -