クライアントでの入力パイプの実装
入力パイプを使用してクライアントからサーバーにデータを転送する場合は、プル プロシージャを実装する必要があります。 プル プロシージャでは、転送するデータを検索し、バッファーにデータを読み取り、送信する要素の数を設定する必要があります。 サーバーがデータをそれ自体にプルし始めるときに、すべてのデータがバッファー内にある必要はありません。 プル プロシージャは、バッファーを増分的に埋めることができます。
送信するデータがこれ以上ない場合、プロシージャは最後の引数を 0 に設定します。 すべてのデータが送信されると、プル プロシージャは、戻る前に必要なクリーンアップを行う必要があります。 [入力、出力] パイプであるパラメーターの場合、プル プロシージャは、すべてのデータが送信された後にクライアントの状態変数をリセットする必要があります。そのため、プッシュ プロシージャはそれを使用してデータを受信できます。
次の例は、プラットフォーム ソフトウェア開発キット (SDK) に含まれている Pipedemo プログラムから抽出されます。
//file: client.c (fragment)
#include <windows.h>
#include "pipedemo.h"
long *globalPipeData;
long globalBuffer[BUF_SIZE];
ulong pipeDataIndex; /* state variable */
void SendLongs()
{
LONG_PIPE inPipe;
int i;
globalPipeData =
(long *)malloc( sizeof(long) * PIPE_SIZE );
for (i=0; i<PIPE_SIZE; i++)
globalPipeData[i] = IN_VALUE;
pipeDataIndex = 0;
inPipe.state = (rpc_ss_pipe_state_t )&pipeDataIndex;
inPipe.pull = PipePull;
inPipe.alloc = PipeAlloc;
InPipe( inPipe ); /* Make the rpc */
free( (void *)globalPipeData );
}//end SendLongs
void PipeAlloc( rpc_ss_pipe_state_t stateInfo,
ulong requestedSize,
long **allocatedBuffer,
ulong *allocatedSize )
{
ulong *state = (ulong *)stateInfo;
if ( requestedSize > (BUF_SIZE*sizeof(long)) )
{
*allocatedSize = BUF_SIZE * sizeof(long);
}
else
{
*allocatedSize = requestedSize;
}
*allocatedBuffer = globalBuffer;
} //end PipeAlloc
void PipePull( rpc_ss_pipe_state_t stateInfo,
long *inputBuffer,
ulong maxBufSize,
ulong *sizeToSend )
{
ulong currentIndex;
ulong i;
ulong elementsToRead;
ulong *state = (ulong *)stateInfo;
currentIndex = *state;
if (*state >= PIPE_SIZE )
{
*sizeToSend = 0; /* end of pipe data */
*state = 0; /* Reset the state = global index */
}
else
{
if ( currentIndex + maxBufSize > PIPE_SIZE )
elementsToRead = PIPE_SIZE - currentIndex;
else
elementsToRead = maxBufSize;
for (i=0; i < elementsToRead; i++)
{
/*client sends data */
inputBuffer[i] = globalPipeData[i + currentIndex];
}
*state += elementsToRead;
*sizeToSend = elementsToRead;
}
}//end PipePull
この例には、MIDL コンパイラによって生成されたヘッダー ファイルが含まれています。 詳細については、「 IDL ファイルでのパイプの定義」を参照してください。 また、globalPipeData というデータ ソースとして使用する変数も宣言します。 変数 globalBuffer は、pull プロシージャが globalPipeData から取得したデータブロックを送信するために使用するバッファーです。
SendLongs 関数は、入力パイプを宣言し、データ ソース変数 globalPipeData にメモリを割り当てます。 クライアント/サーバー プログラムでは、データ ソースは、クライアントが作成するファイルまたは構造体にすることができます。 また、クライアント プログラムでサーバーからデータを取得し、処理し、入力パイプを使用してサーバーに返すこともできます。 この簡単な例では、データ ソースは長整数の動的に割り当てられたバッファーです。
転送を開始する前に、クライアントは状態変数、プル プロシージャ、およびアロケーション プロシージャへのポインターを設定する必要があります。 これらのポインターは、クライアントが宣言するパイプ変数に保持されます。 この場合、SendLongs は inPipe を宣言します。 状態変数には、任意の適切なデータ型を使用できます。
クライアントは、サーバー上でリモート プロシージャを呼び出すことによって、パイプ経由でデータ転送を開始します。 リモート・プロシージャーを呼び出すと、クライアントが送信する準備ができていることがサーバー・プログラムに指示されます。 その後、サーバーはデータをそれ自体にプルできます。 この例では、InPipe というリモート プロシージャを呼び出します。 データがサーバーに転送されると、SendLongs 関数は動的に割り当てられたバッファーを解放します。
バッファーが必要になるたびにメモリを割り当てるのではなく。 この例のアロケーション プロシージャは、変数 globalBuffer へのポインターを設定するだけです。 プル プロシージャは、データを転送するたびにこのバッファーを再利用します。 より複雑なクライアント プログラムでは、サーバーがクライアントからデータをプルするたびに新しいバッファーを割り当てる必要がある場合があります。
クライアント スタブはプル プロシージャを呼び出します。 この例の pull プロシージャでは、状態変数を使用して、読み取り元のグローバル データ ソース バッファー内の次の位置を追跡します。 ソース バッファーからパイプ バッファーにデータを読み取ります。 クライアント スタブは、データをサーバーに送信します。 すべてのデータが送信されると、プル プロシージャによってバッファー サイズが 0 に設定されます。 これにより、データのプルを停止するようにサーバーに指示されます。
関連トピック