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


Реализация выходных каналов на клиенте

При использовании выходного канала для передачи данных с сервера на клиент необходимо реализовать процедуру отправки в клиенте. Процедура отправки принимает указатель на буфер и количество элементов из клиентской заглушки и, если число элементов больше 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. Затем процедура извлечения повторно использует этот буфер при каждой передаче данных. Более сложным клиентским программам может потребоваться выделять новый буфер каждый раз, когда сервер извлекает данные из клиента.

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

Трубы

/Эй