• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • Sun RPC 編程簡介

    發表于:2007-07-13來源:作者:點擊數: 標簽:
    摘要: 本文簡單介紹了RPC(Remote Procedure Call 遠程過程調用)的原理結構、特點, 及其開放給編程人員不同層次的編程接口。并且例舉實例示范如何通過Rpcgen 編譯工 具來快速開發RPC應用。 一、 概述 在傳統的編程概念中,過程是由 程序員 在本地編譯完成

    摘要:  
        本文簡單介紹了RPC(Remote Procedure Call 遠程過程調用)的原理結構、特點,
    及其開放給編程人員不同層次的編程接口。并且例舉實例示范如何通過Rpcgen 編譯工
    具來快速開發RPC應用。

    一、 概述
    在傳統的編程概念中,過程是由程序員在本地編譯完成,并只能局限在本地運行的一段
    代碼,也即其主程序和過程之間的運行關系是本地調用關系。因此這種結構在網絡日益
    發展的今天已無法適應實際需求??偹苤?,傳統過程調用模式無法充分利用網絡上其
    他主機的資源(如CPU、Memory等),也無法提高代碼在實體間的共享程度,使得主機資
    源大量浪費。
    而本文要介紹的RPC編程,正是很好地解決了傳統過程所存在的一系列弊端。通過RPC我
    們可以充分利用非共享內存的多處理器環境(例如通過局域汪連接得多臺工作站),這樣
    可以簡便地將你的應用分布在多臺工作站上,應用程序就像運行在一個多處理器的計算機
    上一樣。你可以方便的實現過程代碼共享,提高系統資源的利用率,也可以將以大量數值
    處理的操作放在處理能力較強的系統上運行,從而減輕前端機的負擔。
    二、 RPC的結構原理及其調用機制
    如前所述RPC其實也是種C/S的編程模式,有點類似C/S Socket 編程模式,但要比它
    更高一層。當我們在建立RPC服務以后,客戶端的調用參數通過底層的RPC傳輸通道,可以
    是UDP,也可以是TCP(也即TI-RPC-無關性傳輸),并根據傳輸前所提供的目的地址及RPC
    上層應用程序號轉至相應的RPC Application Porgramme Server ,且此時的客戶端處于等
    待狀態,直至收到應答或Time Out超時信號。具體的流程圖如F1。當服務器端獲得了請求
    消息,則會根據注冊RPC時告訴RPC系統的例程入口地址,執行相應的操作,并將結果返回
    至客戶端。


    F1
    當一次RPC調用結束后,相應線程發送相應的信號,客戶端程序才會繼續運行。
    當然,一臺服務主機上可以有多個遠程過程提供服務,那么如何來表示一個唯一存
    在的遠程過程呢?一個遠程過程是有三個要素來唯一確定的:程序號、版本號和過程號。
    程序號是用來區別一組相關的并且具有唯一過程好的遠程過程。一個程序可以有一個或幾
    個不同的版本,而每個版本的程序都包含一系列能被遠程調用的過程,通過版本的引入,
    使得不同版本下的RPC能同時提供服務。每個版本都包含有許多可供遠程調用的過程,每個
    過程則有其唯一標示的過程號。
    三、 基于RPC的應用系統開發
    通過以上對RPC原理的簡介后,我們再來繼續討論如何來開發基于RPC的應用系統。
    一般而言在開發RPC時,我們通常分為三個步驟:
    a、 定義說明客戶/服務器的通信協議。
        這里所說的通信協議是指定義服務過程的名稱、調用參數的數據類型和返回參數的數據
        類型,還包括底層傳輸類型(可以是UDP或TCP),當然也可以由RPC底層函數自動選擇
        連接類型建立TI-RPC。最簡單的協議生成的方法是采用協議編譯工具,常用的有Rpcgen,
        我會在后面實例中詳細描述其使用方法。
    b、 開發客戶端程序。
    c、 開發服務器端程序。
    開發客戶端和服務器端的程序時,RPC提供了我們不同層次的開發例程調用接口。不
    同層次的接口提供了對RPC不同程度控制。一般可分為5個等級的編程接口,接下來我們
    分別討論一下各層所提供的功能函數。
    1、 簡單層例程
    簡單層是面向普通RPC應用,為了快速開發RPC應用服務而設計的,他提供
           了如下功能函數。
      函數名              功能描述
    Rpc_reg( ) 在一特定類型的傳輸層上注冊某個過程,來作為提供服務的RPC程序
    Rpc_call( ) 遠程調用在指定主機上指定的過程
    Rpc_Broadcast( )  向指定類型的所有傳輸端口上廣播一個遠程過程調用請求

    2、 高層例程
               在這一層,程序需要在發出調用請求前先創建一個客戶端句柄,或是在偵聽請
       求前先建立一個服務器端句柄。程序在該層可以自由的將自己的應用綁在所有的
    傳輸端口上,它提供了如下功能函數。

      函數名              功能描述
    Clnt_create( )  程序通過這個功能調用,告訴底層RPC服務器的位置及其傳輸類型
    Clnt_create_timed( )  定義每次嘗試連接的超時最大時間
    Svc_create( )  在指定類型的傳輸端口上建立服務器句柄,告訴底層RPC事件過程的相應入口地址
    Clnt_call() 向服務器端發出一個RPC調用請求

    3、 中間層例程
       中間層向程序提供更為詳細的RPC控制接口,而這一層的代碼變得更為復雜,
           但運行也更為有效,它提供了如下功能函數。
      函數名              功能描述
    Clnt_tp_create( )  在指定的傳輸端口上建立客戶端句柄
    Clnt_tp_create_timed( )  定義最大傳輸時延
    Svc_tp_creaet( )  在指定的傳輸端口上建立服務句柄
    Clnt_call( )  向服務器端發出RPC調用請求

    4、 專家層例程
       這層提供了更多的一系列與傳輸相關的功能調用,它提供了如下功能函數。

      函數名              功能描述
    Clnt_tli_create( )  在指定的傳輸端口上建立客戶端句柄
    Svc_tli_create( )  在指定的傳輸端口上建立服務句柄
    Rpcb_set( )  通過調用rpcbind將RPC服務和網絡地址做映射
    Rpcb_unset( )  刪除rpcb_set( ) 所建的映射關系
    Rpcb_getaddr( )  調用rpcbind來犯會指定RPC服務所對應的傳輸地址
    Svc_reg( )  將指定的程序和版本號與相應的時間例程建起關聯
    Svc_ureg( )  刪除有svc_reg( ) 所建的關聯
    Clnt_call( )  客戶端向指定的服務器端發起RPC請求

     


    5、 底層例程
       該層提供了所有對傳輸選項進行控制的調用接口,它提供了如下功能函數。


      函數名              功能描述
    Clnt_dg_create( ) 采用無連接方式向遠程過程在客戶端建立客戶句柄
    Svc_dg_create( )  采用無連接方式建立服務句柄
    Clnt_vc_create( )  采用面向連接的方式建立客戶句柄
    Svc_vc_create( )  采用面向連接的方式建立RPC服務句柄
    Clnt_call( )  客戶端向服務器端發送調用請求
    四、 實例介紹
        以下我將通過實例向讀者介紹通過簡單層RPC的實現方法。通常在此過程中我們
    將使用RPC協議編譯工具-Rpcgen。Rpcgen 工具用來生成遠程程序接口模塊,它將以RPC
    語言書寫的源代碼進行編譯,Rpc 語言在結構和語法上同C語言相似。由Rpcgen 編譯生
    成的C源程序可以直接用C編譯器進行編譯,因此整個編譯工作將分為兩個部分。Rpcgen
    的源程序以.x結尾,通過其編譯將生成如下文件:
    a) 一個頭文件(.h)包括服務器和客戶端程序變量、常量、類型等說明。
    b) 一系列的XDR例程,它可以對頭文件中定義的數據類型進行處理。
    c) 一個Server 端的標準程序框架。
    d) 一個Client 端的標準程序框架。
       當然,這些輸出可以是選擇性的,Rpcgen 的編譯選項說明如下:
      選項 功能
    '-' a 生成所有的模板文件
    '-' Sc 生成客戶端的模板文件
    '-' Ss 生成服務器端的模板文件
    '-' Sm 生成Makefile 文件
    (詳見Solaris Rpcgen Manaul) 

    Rpcgen 源程序 time.x:
    /* time.x: Remote time printing protocol */
    program TIMEPROG {
       version PRINTIMEVERS {
         string PRINTIME(string) = 1;
       } = 1;
    } = 0x20000001;
    time_proc.c源程序:
    /* time_proc.c: implementation of the remote procedure "printime" */ 
    #include <stdio.h> 
    #include <rpc/rpc.h>           /* always needed */ 
    #include "time.h"  /* time.h will be generated by rpcgen */ 
    #include <time.h>         
    /* Remote version of "printime" */ 
    char ** printime_1(char **msg,struct svc_req *req)

    {
       static char * result; /* must be static! */
       static char tmp_char[100];
       time_t rawtime;
       
       FILE *f;

       f = fopen("/tmp/rpc_result", "a+");
       if (f == (FILE *)NULL) {
         strcpy(tmp_char,"Error");
         result = tmp_char;;
         return (&result);
        }
       fprintf(f, "%s\n", *msg); //used for debugging 
       fclose(f);
       time(&rawtime);
       sprintf(tmp_char,"Current time is :%s",ctime(&rawtime));
       result =tmp_char;
       return (&result);
    }
    rtime.c源代碼
    /*
    * rtime.c: remote version
    * of "printime.c"
    */

    #include <stdio.h>
    #include "time.h" /* time.h generated by rpcgen */

    main(int argc, char **argv)

    {
      CLIENT *clnt;
      char *result;
      char *server;
      char *message;
     

     if (argc != 3) {
         fprintf(stderr, "usage: %s host message\n", argv[0]);
         exit(1);
        }

      server = argv[1];
      message = argv[2];

      /*
       * Create client "handle" used for
       * calling TIMEPROG on the server
       * designated on the command line.
       */

      clnt = clnt_create(server, TIMEPROG, PRINTIMEVERS, "visible");

      if (clnt == (CLIENT *)NULL) {
       /*
        * Couldn't establish connection
        * with server.
        * Print error message and die.
        */

       clnt_pcreateerror(server);
       exit(1);
       }

      /*
       
    * Call the remote procedure
       * "printime" on the server
       */

       result =*printime_1(&message,clnt);
       if (result== (char *)NULL) {
         /*
          * An error occurred while calling
          * the server.
          * Print error message and die.
          */

         clnt_perror(clnt, server);
         exit(1);
        }

       /* Okay, we successfully called
        * the remote procedure.
        */

       if (strcmp(result,"Error") == 0) {

       /*
        * Server was unable to print
        * the time.
        * Print error message and die.
        */

        fprintf(stderr, "%s: could not get the time\n",argv[0]);
        exit(1);
        }
        printf("From the Time Server ...%s\n",result);  
        clnt_destroy( clnt );
        exit(0);
    }
       有了以上的三段代碼后,就可用rpcgen 編譯工具進行RPC協議編譯,命令如下:
       $rpcgen time.x
       rpcgen 會自動生成time.h、time_svc.c、time_clnt.c
       再用系統提供的gcc進行C的編譯,命令如下:
       $gcc rtime.c time_clnt.c -o rtime -lnsl //客戶端編譯
    $gcc time_proc.c time_svc.c -o time_server -lnsl //服務器端編譯
    編譯成功后即可在Server端運行time_server,立即將該服務綁定在rpc服務端口上提供
    服務。在客戶端運行./rdate hostname msg (msg 是一字符串,筆者用來測試時建立的),
    立即會返回hostname 端的時間。
         由于,在Sun Solaris 中無法獲取遠端Server 上時鐘信息的功能(不改變本
         地Server時鐘),筆者曾將此程序應用于計費服務器同時鐘服務器同步監測的網管
         系統中,運行穩定,獲得了較好的效果。應該說RPC的應用是十分廣泛的,特別是
         在分布式計算領域中尤為顯得重要。當然,筆者也是剛接觸RPC,還有很多地方了
         解的不夠深刻,望廣大讀者多指教。

     

    參考文獻:
    《SUN Solaris8 ONC+ Dev》

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>