在客户端上实现输出管道

使用输出管道将数据从服务器传输到客户端时,必须在客户端中实现推送过程。 推送过程从客户端存根获取指向缓冲区的指针和元素计数,如果元素计数大于 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 的指针,而不是在每次需要缓冲区时分配内存。 然后,每次传输数据时,拉取过程都会重复使用此缓冲区。 当服务器每次从客户端拉取数据时,更复杂的客户端程序可能需要分配新的缓冲区。

此示例中的推送过程使用状态变量跟踪将在全局数据接收器缓冲区中存储数据的下一个位置。 它将数据从管道缓冲区写入接收器缓冲区。 然后,客户端存根从服务器接收下一个数据块,并将其存储在管道缓冲区中。 发送所有数据后,服务器将传输零大小的缓冲区。 这提示推送过程停止接收数据。

/Oi