ONC+ 開発ガイド

非ブロッキング入出力

非ブロッキング入出力は、接続型プロトコルでの 1 方向性メッセージングにおいて、要求がトランスポート層に受け入れられるのを待つ間に、クライアントがブロックされるのを防ぎます。

接続型のプロトコルでは、ネットワークプロトコルのキューに入れられるデータの量に上限があります。この上限は、使用されるトランスポートプロトコルにより異なります。クライアントが送信している要求がこのデータ上限に達すると、このクライアントは、その要求がキュー内に入るまで、処理をブロックされます。ユーザーは、このメッセージがキューに追加されるまでどのくらいの時間待機するかを特定することはできません。

非ブロッキング入出力では、トランスポートのキューが満杯の場合にクライアントとトランスポート層との間で利用可能な追加バッファーがあります。トランスポートのキューに受け入れられなかった要求をこのバッファー内に格納できるため、クライアントはブロックされません。要求をバッファー内に入れるとすぐに、クライアントは処理を続けることができます。クライアントは、要求がキューに入れられるまで待つことはなく、またバッファーが要求を受け付けた後で要求のステータス情報を受けとることもありません。

非ブロッキング入出力を使用することにより、2 方向性メッセージングや 1 方向性メッセージングに比べてより多くの処理時間を得ることができます。クライアントは、処理の継続をブロックされることなく要求を続けて送信することができます 。

次の図は、入出力モードで非ブロッキングを選択し、 トランスポート層のキューが満杯であるケースを示しています。

図 8–3 非ブロッキングメッセージング

Graphic

非ブロッキング入出力の使用

非ブロッキング入出力を使用するには、clnt_control() 関数の CLSET_IO_MODE rpciomode_t* オプションで RPC_CL_NONBLOCKING 引数を指定して、クライアントハンドルを構成します。詳細は、clnt_control(3NSL) のマニュアルページを参照してください。

トランスポートのキューが満杯の場合には、バッファーが使用されます。次の 2 つの基準が満たされるまで、バッファーが使用され続けます。

その後、トランスポートのキューが満杯になるまで、要求は直接トランスポートのキューに送られます。バッファーのデフォルトのサイズは、16 K バイトです。

バッファーは自動的に空にされるのではないことに留意してください。バッファーにデータが含まれる場合には、ユーザーがバッファーをフラッシュする必要があります。

CLSET_IO_MODE で RPC_CL_NONBLOCKING 引数を選択している場合は、フラッシュモードを選択することができます。CLSET_FLUSH_MODE に RPC_CLBESTEFFORT_FLUSH または RPC_CL_BLOCKING_FLUSH 引数のいずれかを指定できます。また、clnt_call() などの同期コールを送信することにより、バッファーを空にすることもできます。詳細は、clnt_control(3NSL) のマニュアルページを参照してください。

バッファーが満杯の場合は、RPC_CANTSTORE エラーがクライアントに返され、その要求は送られません。クライアントは、後でそのメッセージを再送信する必要があります。CLGET_CONNMAXREC および CLSET_CONNMAXREC コマンドを使用することにより、バッファーのサイズを確認したり、変更したりすることができます。バッファー内に格納されている、すべての保留状態の要求のサイズを確認する場合は、CLGET_CURRENT_REC_SIZE コマンドを使用します。これらのコマンドについての詳細は、clnt_control(3NSL) のマニュアルページを参照してください。

サーバーは、要求が受け付けられたかどうかや処理されたかどうかの確認は行いません。ユーザーは、要求がバッファーに入った後で clnt_control() を使用すると、要求のステータス情報を入手することができます。

非ブロッキング入出力で単純なカウンターを使用する

次に例を示す client.c ファイルは、非ブロッキング入出力モードの使用法を例示するために、変更されています。この新しい client_nonblo.c ファイルでは、RPC_CL_NONBLOCKING 引数の使用により入出力モードが非ブロッキングに指定されており、RPC_CL_BLOCKING_FLUSH の使用によりフラッシュモードがブロッキングに選択されています。入出力モードおよびフラッシュモードは、CLSET_IO_MODE で呼び出されます。エラーが発生すると、RPC_CANT_STORE がクライアントに返され、プログラムによりバッファーのフラッシュが試みられます。フラッシュの別のメソッドを選択するには、clnt_control(3NSL) のマニュアルページを参照してください。

#include <stdio.h>
#include "counter.h"

main(int argc, char *argv[])
{
    CLIENT* clnt;
    enum clnt_stat result;
    char *server;
    int number;
    bool_t bres;
		/* 
		 * 使用する入出力モードとフラッシュメソッドを選択する。
		 * この例では、非ブロッキング入出力モードと 
		 * ブロッキングフラッシュが選択されている。
		 */
    int mode = RPC_CL_NONBLOCKING;
    int flushMode = RPC_CL_BLOCKING_FLUSH;

    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);
    }

		/* 
 	 * clnt_control を使用して入出力モードを設定する。
 	 * この例では、非ブロッキング入出力モードが
 	 * 選択されている。
 	 */
    bres = clnt_control(clnt, CLSET_IO_MODE, (char*)&mode);
    if (bres)
	    /* 
		  * フラッシュモードをブロッキングに設定する
		  */
        bres = clnt_control(clnt, CLSET_FLUSH_MODE, (char*)&flushMode);

    if (!bres) {
        clnt_perror(clnt, "clnt_control");
        exit(1);
    }
		 /* 
 	  * RPC サービスを呼び出す。
 	  */
    result = add_1(number, clnt);

    switch (result) {
    case RPC_SUCCESS:
        fprintf(stdout,"Success\n");
        break;
		/*
 	 * RPC_CANTSTORE は、バッファーが要求を格納できない場合に、 
		 * クライアントに返される新しい値。
		 */
    case RPC_CANTSTORE:
        fprintf(stdout,"RPC_CANTSTORE error. Flushing ... \n");
		/*
		 * バッファーは、ブロッキングフラッシュを使用してフラッシュされる
		 */
			  bres = clnt_control(clnt, CLFLUSH, NULL);
        if (!bres) {
	    		   clnt_perror(clnt, "clnt_control");
			  }
        break;
    default:
			  clnt_perror(clnt, "call failed");
        break;
    }

    /* フラッシュする */
    bres = clnt_control(clnt, CLFLUSH, NULL);
    if (!bres) {
			  clnt_perror(clnt, "clnt_control");
    }

    clnt_destroy(clnt);
    exit(0);
}

非ブロッキングとして構成したときの clnt_call()

1 方向性メッセージングには、clnt_send() を使用します。クライアントが要求をサーバーに送信する際、応答を待機しないので、タイムアウトは適用されません。

2 方向性メッセージングには、clnt_call() を使用します。サーバーが応答を送信するかエラーのステータスメッセージを送信するか、またはクライアントサイドでタイムアウトが発生するまで、クライアントはブロックされたままになります。

非ブロッキング機能では、2 方向性と 1 方向性のコールを共に送信することができます。RPC_CL_NONBLOCKING 入出力モードを使用し、非ブロッキングとして構成したクライアントサイドで clnt_call() を使用すると、次のような動作の変更があります。2 方向性の要求がバッファーに送られると、バッファー内にすでに入っている 1 方向性のすべての要求が、その 2 方向性の要求が処理される前にトランスポート層を介して送られます。バッファーを空にするための時間は、2 方向性コールのタイムアウトにはカウントされません。詳細は、clnt_control(3NSL) のマニュアルページを参照してください。