ONC+ 開発ガイド

1 方向性メッセージング

1 方向性メッセージングでは、クライアントスレッドがメッセージを含む要求をサーバーに送信します。クライアントスレッドはサーバーからの応答を待つことなく、その要求がトランスポート層に受け入れられたら処理を進めることができます。その要求はトランスポート層によって常にすぐサーバーに送信されるとは限りませんが、トランスポート層に送信されるまでキューで待機します。サーバーは、要求内に含まれるメッセージを処理することによって、受け取った要求を実行します。この方式によって、処理時間が短縮されます。

次の図で、1 方向性メッセージングを示します。

図 8–1 1 方向性メッセージング

Graphic

Sun RPC ライブラリの以前のバージョンでは、ほとんどの要求は 2 方向性メッセージングにより送られていました。2 方向性メッセージングでは、クライアントスレッドは処理を進める前にサーバーからの応答を得るまで待つ必要があります。クライアントスレッドが一定の時間内にサーバーからの応答を受け取らなかった場合、タイムアウトになります。このクライアントスレッドは、1 番目の要求が実行されるかタイムアウトになるまで、2 番目の要求を送ることができません。 次の図に、メッセージングのメソッドを示します。

図 8–2 2 方向性メッセージング

Graphic

Sun RPC ライブラリの以前のバージョンには、バッチングと呼ばれるもう 1 つのメッセージング方法があります。この方法では、グループ中の要求が同時に処理可能の間、クライアントの要求はキューに保持されます。これは 1 方向性メッセージングの形態です。詳細は、第 4 章「RPC プログラマインタフェース」 を参照してください。

トランスポート層が要求を受け取った後は、クライアントは転送の失敗を通知されることはなく、またサーバーから要求を受け取った旨を通知されることもありません。たとえば、サーバーが認証上の問題により要求を拒否した場合は、クライアントはこの問題を通知されることはありません。トランスポート層が要求を受け入れなかった場合は、送信オペレーションにより直ちにエラーがクライアントに返されます。

サーバーが正しく機能していることをチェックする必要がある場合は、2 方向性の要求をサーバーに送信してみます。この要求により、サーバーが利用可能であり、クライアントから送信された 1 方向性要求をサーバーが受信中かを判定することができます。

1 方向性のメッセージングには、clnt_send() 関数が Sun RPC ライブラリに追加され、oneway 属性が RPC 文法に追加されています。

clnt_send()

Sun RPC ライブラリの以前のバージョンでは、リモートプロシージャコールの送信に clnt_call() 関数を使用していました。拡張された 1 方向性のメッセージングサービスでは、clnt_send() 関数が 1 方向性のリモートプロシージャコールを送信します。

クライアントが clnt_send() を呼び出す際は、クライアントはサーバーに要求を送信し、処理を続行します。要求がサーバーに到着すると、サーバーは着信要求を処理するためにディスパッチルーチンを呼び出します。

clnt_send() 関数は、clnt_call() と同様、サービスへアクセスするためにクライアントハンドルを使用します。詳細は、clnt_send(3NSL) および clnt_call(3NSL) のマニュアルページを参照してください。

clnt_create() に適切なバージョン番号を指定しない場合、clnt_call() は失敗します。clnt_send() は、サーバーがステータスを返さないため、同じ状況では失敗を報告しません。

oneway 属性

1 方向性メッセージングを使用するには、oneway キーワードをサーバー関数の XDR 定義 に追加します。oneway キーワードを使用する場合は、rpcgen によって生成されるスタブは clnt_send() を使用します。ユーザーは次のいずれかを行うことができます:

1 方向性メッセージングには、rpcgen コマンドのバージョン1.1 を使用してください。

oneway キーワードを宣言する際は、次の構文を使用する RPC 言語の仕様に従ってください:

"oneway" function-ident "(" type-ident-list ")" "=" value;

RPC 言語の仕様についての詳細は、付録 B 「RPC プロトコルおよび言語の仕様」 を参照してください。

オペレーションに oneway 属性を宣言する際は、サーバーサイドには何の結果も作成されず、クライアントには何のメッセージも返されません。

次に示す oneway 属性の情報を、RPC 言語の仕様 の 「RPC 言語定義」の表に追加する必要があります。

単純なカウンターサービスを使用する、1 方向性コール

このセクションでは、単純なカウンターサービスにおいて 1 方向性のプロシージャを使用する方法を例示しています。このカウンターサービスでは、ADD() 関数が、使用できる唯一の関数です。各リモート呼び出しは整数を送信し、この整数は、サーバーによって管理されるグローバルカウンターに追加されます。このサービスを使用するため には、RPC 言語定義に oneway 属性を宣言する必要があります。

この例では、-M-N、および -C rpcgen オプションを使用してスタブを生成します。これらのオプションを指定することにより、マルチスレッド対応のスタブが生成され、複数の入力パラメータを受け入れ可能となり、生成されたヘッダーは ANSI C++ に適合するようになります。スタブが変わらないので引数を渡すセマンティクスがより明確であり、アプリケーションへのスレッドの追加がより簡単になるため、クライアントおよびサーバーアプリケーションがシングルスレッドであっても、これらの rpcgen オプションを使用してください。

  1. 最初に、 counter.x にサービスを記述します。

       /* counter.x: リモートカウンタープロトコル */
    program COUNTERPROG {
     	version COUNTERVERS {
     	  oneway ADD(int) = 1;
     	} = 1;
    } = 0x20000001;

    このサービスは、プログラム番号 (COUNTERPROG) 0x200000001、バージョン番号 (COUNTERVERS) 1 を持ちます。

  2. counter.x ファイルに rpcgen を呼び出します。

    rpcgen -M -N -C counter.x

    これにより、クライアントおよびサーバーのスタブ counter.hcounter_clnt.ccounter_svc.c が生成されます。

  3. server.c ファイルに示されているように、サーバーサイド用のサービスハンドラ、およびハンドラに割り当てられたメモリー領域を解放するために使用される counterprog_1_freeresult() 関数を記述します。サーバーがクライアントへ応答を送信する時に、RPC ライブラリがこの関数を呼び出します。

    	  #include <stdio.h>
    #include "counter.h"
    
    int counter = 0;
    
      	 bool_t
    add_1_svc(int number, struct svc_req *rqstp)
    {
     	 bool_t retval = TRUE;
    
      	 counter = counter + number;
    
      	 return retval;
    }
     	 int
    counterprog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t
                             result)
    {
     	 (void) xdr_free(xdr_result, result);
    
      	 /*
    		  * 必要であれば、ここに解放のための追加コードを挿入する
    		  */
    
      	 return TRUE;
    }

    サービスハンドラ、counter_svc.c スタブをコンパイルおよびリンクして、サーバーを構築します。このスタブには、TI-RPC の初期化および処理に関する情報が含まれています。

  4. 次に、クライアントアプリケーションである client.c を記述します。

    	  #include <stdio.h>
    #include "counter.h"
    
    main(int argc, char *argv[])
    {
     	 CLIENT *clnt;
     	 enum clnt_stat result;
     	 char *server;
     	 int number;
    
      	 if(argc !=3) {
     		  fprintf(stderr, "usage: %s server_name number\n", argv[0];
    			  exit(1);
    	 	 }
     	 server = argv[1];
     	 number = atoi(argv[2]);
    
      	 /* 
    		  * クライアントハンドルを作成する
    		  */
     	 clnt = clnt_create(server, COUNTERPROG, COUNTERVERS, "tcp");
    
      	 if(clnt == (CLIENT *)NULL) {
    		 /* 
    		  * 接続を確立できなかった
    		  */
    	 		  clnt_pcreateerror(server);
     		  exit(1);
     	 }
    
      	 result = add_1(number, clnt);
     	 if (result !=RPC_SUCCESS) {
     		  clnt_perror(clnt, "call failed");
     	 }
    
      	 clnt_destroy(clnt);
     	 exit(0); 
    }

    add_1() クライアント関数は、リモート関数用に生成された counter_clnt.c スタブです。

    クライアントを構築するには、クライアントの main および counter_clnt.c をコンパイルおよびリンクします。

  5. ./server と入力して、構築したサーバーを起動します。

  6. 最後に、次のように別のシェルからサービスを起動します。./client servername23

    23 は、グローバルカウンターに追加される番号です。