Поделиться через


Реализация трубопроводов ввода данных на стороне клиента

При использовании входного канала для передачи данных с клиента на сервер необходимо реализовать процедуру извлечения. Процедура извлечения должна найти передаваемые данные, считывать данные в буфер и задавать количество элементов для отправки. Не все данные должны находиться в буфере, когда сервер начинает забирать их. Процедура извлечения может постепенно заполнить буфер.

Если для отправки данных больше нет, процедура задает для последнего аргумента значение нулю. При отправке всех данных процедура извлечения должна выполнить любую необходимую очистку перед возвратом. Для параметра, являющегося каналом [in, out], процедура извлечения должна обнулить переменную состояния клиента после передачи всех данных, чтобы процедура push могла использовать её для получения данных.

Следующий пример извлекается из программы 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 освобождает динамически выделенный буфер.

Вместо выделения памяти каждый раз, когда требуется буфер. Процедура alloc в этом примере просто устанавливает указатель на переменную globalBuffer. Процедура извлечения повторно использует этот буфер при каждом передаче данных. Более сложным клиентским программам может потребоваться выделение нового буфера каждый раз, когда сервер извлекает данные из клиента.

Заглушка клиента вызывает процедуру извлечения. Процедура извлечения в этом примере использует переменную состояния для отслеживания следующей позиции в глобальном буфере источника данных, из которого происходит чтение. Он считывает данные из исходного буфера в буфер канала. Заглушка клиента передает данные серверу. Когда все данные были отправлены, процедура извлечения задает размер буфера равным нулю. Это сообщает серверу прекратить извлечение данных.

труба

/Oi