次の方法で共有


クライアントでの出力パイプの実装

出力パイプを使用してサーバーからクライアントにデータを転送する場合は、クライアントにプッシュ プロシージャを実装する必要があります。 プッシュ プロシージャは、クライアント スタブからバッファーと要素数へのポインターを受け取り、要素数が 0 より大きい場合はデータを処理します。 たとえば、スタブのバッファーから独自のメモリにデータをコピーできます。 または、スタブのバッファー内のデータを処理し、ファイルに保存することもできます。 要素数が 0 の場合、プッシュ プロシージャは、戻る前に必要なクリーンアップ タスクを完了します。

次の例では、クライアント関数 ReceiveLongs によってパイプ構造とグローバル メモリ バッファーが割り当てられます。 構造体を初期化し、リモート プロシージャ呼び出しを行い、メモリを解放します。

//file: client.c (fragment)
#include <windows.h>
#include "pipedemo.h"
long *  globalPipeData;
long    globalBuffer[BUF_SIZE];
 
ulong   pipeDataIndex; /* state variable */
 
void ReceiveLongs()
{
    LONG_PIPE *outputPipe;
    idl_long_int i;
 
    globalPipeData =
        (long *)malloc( sizeof(long) * PIPE_SIZE );
    
    pipeDataIndex = 0;
    outputPipe.state =  (rpc_ss_pipe_state_t )&pipeDataIndex;
    outputPipe.push  = PipePush;
    outputPipe.alloc = PipeAlloc;
 
    OutPipe( &outputPipe ); /* Make the rpc */
 
    free( (void *)globalPipeData );
 
}//end ReceiveLongs()

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 PipePush( rpc_ss_pipe_state_t stateInfo,
               long *buffer,
               ulong numberOfElements )
{
    ulong elementsToCopy, i;
    ulong *state = (ulong *)stateInfo;

    if (numberOfElements == 0)/* end of data */
    {
        *state = 0; /* Reset the state = global index */
    }
    else
    {
        if (*state + numberOfElements > PIPE_SIZE)
            elementsToCopy = PIPE_SIZE - *state;
        else
            elementsToCopy = numberOfElements;
 
        for (i=0; i <elementsToCopy; i++)
        { 
            /*client receives data */
            globalPipeData[*state] = buffer[i];
            (*state)++;
        }
    }
}//end PipePush

この例には、MIDL コンパイラによって生成されたヘッダー ファイルが含まれています。 詳細については、「 IDL ファイルでのパイプの定義」を参照してください。 また、データ シンクとして使用する変数 globalPipeData も宣言します。 変数 globalBuffer は、プッシュ プロシージャが globalPipeData に格納するデータブロックを受信するために使用するバッファーです。

ReceiveLongs 関数はパイプを宣言し、グローバル データ シンク変数のメモリ領域を割り当てます。 クライアント/サーバー プログラムでは、データ シンクは、クライアントが作成するファイルまたはデータ構造にすることができます。 この簡単な例では、データ ソースは長整数の動的に割り当てられたバッファーです。

データ転送を開始するには、クライアント・プログラムが出力パイプ構造を初期化する必要があります。 状態変数、プッシュ プロシージャ、およびアロケーション プロシージャへのポインターを設定する必要があります。 この例では、出力パイプ変数を outputPipe と呼びます。

クライアントは、サーバーでリモート プロシージャを呼び出すことによって、データを受信する準備ができていることをサーバーに通知します。 この例では、リモート プロシージャは OutPipe と呼ばれます。 クライアントがリモート プロシージャを呼び出すと、サーバーはデータ転送を開始します。 データが到着するたびに、クライアント スタブは必要に応じてクライアントのアロケーションプロシージャとプッシュプロシージャを呼び出します。

この例のアロケーション プロシージャは、バッファーが必要になるたびにメモリを割り当てるのではなく、変数 globalBuffer へのポインターを設定するだけです。 その後、プル プロシージャは、データを転送するたびにこのバッファーを再利用します。 より複雑なクライアント プログラムでは、サーバーがクライアントからデータをプルするたびに新しいバッファーを割り当てる必要がある場合があります。

この例のプッシュ プロシージャでは、状態変数を使用して、グローバル データ シンク バッファーにデータを格納する次の位置を追跡します。 パイプ バッファーからシンク バッファーにデータを書き込みます。 次に、クライアント スタブはサーバーから次のデータ ブロックを受信し、パイプ バッファーに格納します。 すべてのデータが送信されると、サーバーは 0 サイズのバッファーを送信します。 これにより、プッシュ プロシージャがデータの受信を停止します。

パイプ

/大井