Реализация входных каналов на клиенте
При использовании входного канала для передачи данных с клиента на сервер необходимо реализовать процедуру извлечения. Процедура по запросу должна найти передаваемые данные, считывать данные в буфер и задать количество отправляемых элементов. Не все данные должны находиться в буфере, когда сервер начинает извлекать данные в себя. Процедура извлечения может заполнять буфер добавочным образом.
Если больше нет данных для отправки, процедура устанавливает для последнего аргумента нулевое значение. После отправки всех данных процедура извлечения должна выполнить необходимую очистку перед возвратом. Для параметра, который является каналом [вход, выход], процедура извлечения должна сбросить переменную состояния клиента после передачи всех данных, чтобы процедура отправки могло использовать ее для получения данных.
Следующий пример извлекается из программы Pipedemo, входящей в состав пакета SDK для платформы.
//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. Процедура извлечения повторно использует этот буфер при каждой передаче данных. Более сложным клиентским программам может потребоваться выделить новый буфер каждый раз, когда сервер извлекает данные из клиента.
Заглушка клиента вызывает процедуру извлечения. Процедура извлечения в этом примере использует переменную состояния для отслеживания следующей позиции в глобальном буфере источника данных для чтения. Он считывает данные из исходного буфера в буфер канала. Клиентская заглушка передает данные на сервер. После отправки всех данных процедура извлечения устанавливает нулевой размер буфера. Это указывает серверу прекратить извлечение данных.
Связанные темы