在客户端上实现输入管道
使用输入管道将数据从客户端传输到服务器时,必须实现拉取过程。 拉取过程必须找到要传输的数据,将数据读入缓冲区,并设置要发送的元素数。 当服务器开始向自身拉取数据时,并非所有数据都必须在缓冲区中。 拉取过程可以增量填充缓冲区。
如果没有更多要发送的数据,该过程将其最后一个参数设置为零。 发送所有数据后,拉取过程应在返回之前执行任何所需的清理。 对于作为 [in, out] 管道的参数,拉取过程必须在传输所有数据后重置客户端的状态变量,以便推送过程可以使用它来接收数据。
以下示例是从平台软件开发工具包 (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 是拉取过程用来发送从 globalPipeData 获取的数据块的缓冲区。
SendLongs 函数声明输入管道,并为数据源变量 globalPipeData 分配内存。 在客户端/服务器程序中,数据源可以是客户端创建的文件或结构。 还可以让客户端程序从服务器获取数据、对其进行处理,并使用输入管道将其返回到服务器。 在此简单示例中,数据源是动态分配的长整数缓冲区。
在传输开始之前,客户端必须设置指向状态变量、拉取过程和分配过程的指针。 这些指针保留在客户端声明的管道变量中。 在本例中,SendLongs 声明 inPipe。 可以为状态变量使用任何适当的数据类型。
客户端通过在服务器上调用远程过程来启动跨管道的数据传输。 调用远程过程会告知服务器程序客户端已准备好传输。 然后,服务器可以将数据拉取到自身。 此示例调用名为 InPipe 的远程过程。 将数据传输到服务器后,SendLongs 函数释放动态分配的缓冲区。
而不是每次需要缓冲区时分配内存。 此示例中的分配过程只是设置指向变量 globalBuffer 的指针。 每次传输数据时,拉取过程都会重复使用此缓冲区。 在服务器每次从客户端拉取数据时,更复杂的客户端程序可能需要分配新的缓冲区。
客户端存根调用拉取过程。 此示例中的拉取过程使用 state 变量跟踪要从中读取的全局数据源缓冲区中的下一个位置。 它将源缓冲区中的数据读取到管道缓冲区。 客户端存根将数据传输到服务器。 发送所有数据后,拉取过程会将缓冲区大小设置为零。 这会告知服务器停止拉取数据。
相关主题