Udostępnij przez


Implementowanie potoków wejściowych na kliencie

W przypadku używania potoku wejściowego do transferu danych z klienta do serwera należy zaimplementować procedurę ściągania. Procedura ściągania musi znaleźć dane, które mają zostać przesłane, odczytać dane do buforu i ustawić liczbę elementów do wysłania. Nie wszystkie dane muszą znajdować się w buforze, gdy serwer zacznie ściągać dane do siebie. Procedura ściągania może wypełniać bufor przyrostowo.

Gdy nie ma więcej danych do wysłania, procedura ustawia ostatni argument na zero. Po wysłaniu wszystkich danych procedura ściągnięcia powinna wykonać wszelkie potrzebne oczyszczanie przed zwróceniem. W przypadku parametru będącego potokiem [in, out] procedura pobierania musi zresetować zmienną stanu klienta po przesłaniu wszystkich danych, aby procedura przesyłania mogła używać go do odbierania danych.

Poniższy przykład został wyodrębniony z programu Pipedemo dołączonego do zestawu Sdk (Platform Software Development Kit).

//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

Ten przykład zawiera plik nagłówka wygenerowany przez kompilator MIDL. Aby uzyskać szczegółowe informacje, zobacz Definiowanie potoków w plikach IDL. Deklaruje również zmienną używaną jako źródło danych o nazwie globalPipeData. Zmienna globalBuffer jest buforem używanym przez procedurę ściągania do wysyłania bloków danych uzyskanych z globalPipeData.

Funkcja SendLongs deklaruje potok wejściowy i przydziela pamięć dla zmiennej źródła danych globalPipeData. W programie klienta/serwera źródło danych może być plikiem lub strukturą tworzoną przez klienta. Program kliencki może również uzyskać dane z serwera, przetworzyć je i zwrócić do serwera za pomocą potoku wejściowego. W tym prostym przykładzie źródło danych jest dynamicznie przydzielonym buforem długich liczb całkowitych.

Przed rozpoczęciem transferu klient musi ustawić wskaźniki na zmienną stanu, procedurę ściągania i procedurę alokowania. Te wskaźniki są przechowywane w zmiennej potoku zadeklarowanej przez klienta. W takim przypadku SendLongs deklaruje inPipe. Możesz użyć dowolnego odpowiedniego typu danych dla zmiennej stanu.

Klienci inicjują transfery danych przez potok, wywołując zdalną procedurę na serwerze. Wywołanie procedury zdalnej informuje program serwera, że klient jest gotowy do przesyłania. Następnie serwer może ściągnąć dane do siebie. W tym przykładzie wywoływana jest procedura zdalna o nazwie InPipe. Po przesłaniu danych na serwer funkcja SendLongs zwalnia dynamicznie przydzielony bufor.

Zamiast przydzielać pamięć za każdym razem, gdy potrzebny jest bufor. procedura alokowania w tym przykładzie po prostu ustawia wskaźnik na zmienną globalBuffer. Procedura ściągania ponownie używa tego buforu za każdym razem, gdy przesyła dane. Bardziej złożone programy klienckie mogą wymagać przydzielenia nowego buforu za każdym razem, gdy serwer pobiera dane z klienta.

Element wycinkowy klienta wywołuje procedurę ściągania. Procedura ściągania w tym przykładzie używa zmiennej stanu do śledzenia następnej pozycji w globalnym buforze źródła danych do odczytu. Odczytuje dane z buforu źródłowego do buforu potoku. Stub klienta przesyła dane do serwera. Po wysłaniu wszystkich danych procedura ściągania ustawia rozmiar buforu na zero. Spowoduje to zatrzymanie ściągania danych przez serwer.

rura

/Oi