開放網路運算遠程過程調用

開放網路運算遠程過程調用

開放網路運算遠程過程調用是一種被廣泛套用的遠程過程調用(RPC)系統,是一種屬於套用層的協定堆疊,底層為TCP/IP協定。開放網路運算(ONC)最早源自於太陽微系統(Sun),是網路檔案系統計畫的一部分,因此它經常也被稱為Sun ONCSun RPC。現今在多數類UNIX系統上都實現了這套系統,微軟公司也以Windows Services for UNIX在他們產品上提供ONC RPC的支持。2009年,太陽微系統以標準三條款的BSD許可證發布這套系統。2010年,收購了太陽微系統的甲骨文公司確認了這套軟體BSD許可證的有效性與適用範圍。

基本介紹

  • 中文名:開放網路運算遠程過程調用
  • 外文名:Open Network Computing Remote Procedure Call
簡介,實例,

簡介

Sun Microsystems是首批為RPC支持庫和RPC編譯器提供商業化支持的公司之一。在20世紀80年代由Sun公司提供並支持Sun公司的網路檔案系統(NFS)。由Sun和AT&T牽頭,該協定被推動成為開放式網路計算的標準。它是一個輕量級的RPC系統,並可以在大多數的POSIX和類POSIX的作業系統上可用,包括了Linux,SunOS,OSX以及各種版本的BSD。它通常被稱之為Sun RPC或者是ONC RPC。
ONC RPC提供了一個編譯器,它接受遠程過程接口的定義,並生成客戶機和伺服器的存根函式。這個編譯器叫做rpcgen。在運行這個編譯器之前,程式設計師必須提供接口的定義。接口定義包含了函式聲明,它們按版本號分組,並由一個惟一的程式編號來標識。這個程式編號就使得客戶端能夠識別他們需要的接口。版本號對於那些沒有更新到最新代碼的客戶端來說是非常重要的,它確保這個客戶端仍然能夠連線到一個新的伺服器,只要這個伺服器依然支持舊的函式接口。
在網路中傳輸的參數被編組成為一種被稱之為XDR(eXternalDataRepresentation)的隱式序列化格式。這就確保了可以將參數傳送到可能使用不同位元組順序、不同大小整數、或不同浮點或字元串表示的異構系統中。最後,Sun RPC提供了一個運行時庫,它實現了支持RPC的必要協定和Socket例程。

實例

所有的程式設計師都必須要編寫客戶端代碼,伺服器函式,以及一個RPC接口定義。
客戶端程式
#include <stdlib.h> #include <stdio.h> #include <rpc/rpc.h> #include <netconfig.h> #include "date.h"  main(argc, argv) int argc; char **argv; {     CLIENT *cl;    /* rpc handle */     char *server;     long *lresult;    /* return from bin_date_1 */     char **sresult;    /* return from str_date_1 */      if (argc != 2) {         fprintf(stderr, "usage:  %s hostnamen", argv[0]);         exit(1);     }     server = argv[1];    /* get the name of the server */      /* create the client handle */     if ((cl=clnt_create(server, DATE_PROG,                      DATE_VERS, "netpath")) == NULL) {         /* failed! */         clnt_pcreateerror(server);         exit(1);     }      /* call the procedure bin_date */     if ((lresult=bin_date_1(NULL, cl))==NULL) {         /* failed ! */         clnt_perror(cl, server);         exit(1);     }     printf("time on %s is %ldn", server, *lresult);      /* have the server convert the result to a date string */     if ((sresult=str_date_1(lresult, cl)) == NULL) {         /* failed ! */         clnt_perror(cl, server);         exit(1);     }      printf("date is %sn", *sresult);     clnt_destroy(cl);    /* get rid of the handle */     exit(0); }
服務端程式
 #include <rpc/rpc.h> #include "date.h"  /* bin_date_1 returns the system time in binary format */  long * bin_date_1() {     static long timeval;    /* must be static!! This value is */                     /* used by rpc after bin_date_1 returns */     long time();        /* Unix time function; returns time */      timeval = time((long *)0);     return &timeval; }  /* str_date_1 converts a binary time into a date string */  char ** str_date_1(bintime) long *bintime; {     static char *ptr;    /* return value... MUST be static! */     char *ctime();    /* Unix library function that does the work */     ptr = ctime(bintime);     return &ptr; }
RPC接口定義
 /* date.x - description of remote date service */  /* we define two procedures:                     */ /*   bin_date_1 returns the time in binary format         */ /*        (seconds since Jan 1, 1970 00:00:00 GMT)     */ /*   str_date_1 converts a binary time to a readable date string */  program DATE_PROG {     version DATE_VERS {         long BIN_DATE(void)  = 1;    /* procedure number = 1 */         string STR_DATE(long)  = 2;    /* procedure number = 2 */     } = 1; } = 0x31415926;
當使用rpcgen編譯RPC接口定義(檔案後綴為.x;例如,名為date.x的檔案)時,會創建三個或四個檔案。這些用於date.x示例:
當這個RPC接口定義檔案date.x被rpcgen編譯器編譯的時候,它會生成3個或者4個檔案。
  • date.h
包含程式的定義、版本和函式的聲明。客戶端和伺服器函式都應該包含這個檔案。
  • date_svc.c
實現伺服器存根的代碼。
  • date_clnt.c
實現客戶端存根的代碼。
  • date_xdr.c
包含將數據轉換為XDR格式的XDR例程。如果生成此檔案,則應將其編譯並連結到客戶端和伺服器函式。
創建客戶端和伺服器執行檔的第一步便是編譯接口定義檔案date.x。在此之後,客戶端和伺服器的函式都可以被編譯,並與rpcgen生成的各自的存根函式相關聯。
在舊的RPC版本中,我們要么使用字元串“tcp”,要么使用字元串“udp”來作為其網路傳輸的協定。此做法依然適用,在RPC的Linux實現中,這甚至是一個必需的做法。為了使接口能夠更加靈活,UNIX System v4(SunOS v5)網路選擇例程允許一個更為通用的規範。他們通過搜尋一個/etc/netconfig的檔案,來找到第一個滿足需求的提供者。最後一個參數可以是:
  • “netpath”
搜尋一個NETPATH環境變數,作為傳輸協定的首選
  • “circuit_n”
在NETPATH列表中找到第一個虛擬電路提供程式,“datagram_n”(在NETPATH列表中找到第一個數據報提供程式)
  • “visible”
在/etc/netconfig中找到第一個可見的傳輸提供程式
  • “circuit_v”
在/etc/netconfig中找到第一個可見的虛擬電路傳輸提供程式
  • “datagram_v”
在/etc/netconfig中找到第一個可視數據報傳輸提供程式。
遠程過程調用在設計之初僅支持單一的參數,在之後的發展過程中,逐步改進以支持多個參數的傳遞。在一些rpcgen的版本中,依然默認支持單一的參數,例如蘋果的OSX作業系統。為了能夠支持多個參數,我們需要首先定義一個結構,讓它包含所有的參數數據,初始化它並傳遞這個數據結構。
遠程過程調用返回一個指向結果的指針而並非結果本身。因此,服務端的函式也必須因此而做出改動,使其可以接受一個指向一個在RPC接口定義檔案中定義的值的指針來作為入參,並返回一個指向結果的指針來作為返回結果。在伺服器端,指針必須指向一個靜態的數據,否則,在過程的框架被釋放或者調用過程返回時,該指針會指向一個未定義的區域。在客戶端,這個返回指針可以讓我們區分出一個失敗的RPC結果(空指針)或者是一個null返回結果(間接的null指針)。
RPC 過程的名稱若在 RPC 定義檔案中做了定義,則會轉換為小寫,並在後綴加下劃線,後跟一個版本號。例如,BIN_DATE將會被轉成為引用函式 bin_date_1 。你的伺服器端代碼必須實現 bin_date_1。
運行結果
服務端
當伺服器啟動的時候,伺服器存根函式將會在後台進程中運行(如果當你不再需要使用這個存根函式的時候,你可以通過ps的指令來找到對應的進程,並結束此進程)。存根函式會創建一個Socket並把本地任一個可用的連線埠綁定到此新建的Socket上。緊接著它便會調用一個svc_register的RPC庫函式,通過port mapper來註冊程式的版本跟編號。這個port mapper是另外一個獨立的進程,在伺服器啟動時便會運行。它負責追蹤連線埠號,本版號以及程式編號。在Unix System v4系統中,這個進程稱之為rpcbind;在Linux,OSX以及BSD系統中,它被稱之為portmap。
客戶端
當我們啟動客戶端代碼的時候,它便會利用遠程系統的名稱,程式編號,版本號以及傳輸協定來調用一個clnt_creat函式。它通過遠程系統上的port mapper,在系統上找到合適的連線埠。
客戶端緊接著調用RPC存根函式(例如以上的例子,調用bin_date_1)。這個存根函式便會向伺服器端傳送一條訊息並等待返回結果。
服務端接收到來自客戶端的訊息,接著調用服務端的函式(服務端的bin_date_1函式),處理完畢之後將結果返回給客戶端存根。客戶端存根再把結果返回給調用的最終客戶端代碼。
整個過程可以參照概述圖。

相關詞條

熱門詞條

聯絡我們