Condividi tramite


Implementazione delle pipe di input nel client

Quando si usa una pipe di input per trasferire i dati dal client al server, è necessario implementare una procedura pull. La procedura pull deve trovare i dati da trasferire, leggere i dati nel buffer e impostare il numero di elementi da inviare. Non tutti i dati devono trovarsi nel buffer quando il server inizia a eseguire il pull dei dati in se stesso. La routine pull può riempire il buffer in modo incrementale.

Quando non sono presenti altri dati da inviare, la routine imposta l'ultimo argomento su zero. Quando vengono inviati tutti i dati, la procedura pull deve eseguire qualsiasi pulizia necessaria prima di restituire . Per un parametro che è una pipe [in, out] la routine pull deve reimpostare la variabile di stato del client dopo che tutti i dati sono stati trasmessi, in modo che la procedura push possa usarla per ricevere i dati.

L'esempio seguente viene estratto dal programma Pipedemo incluso in Platform Software Development Kit (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

Questo esempio include il file di intestazione generato dal compilatore MIDL. Per informazioni dettagliate, vedere Definizione di pipe nei file IDL. Dichiara inoltre una variabile usata come origine dati denominata globalPipeData. La variabile globalBuffer è un buffer usato dalla routine pull per inviare i blocchi di dati ottenuti da globalPipeData.

La funzione SendLongs dichiara la pipe di input e alloca la memoria per la variabile di origine dati globalPipeData. Nell'applicazione client/server l'origine dati può essere un file o una struttura creata dal client. È anche possibile ottenere dati dal server, elaborarlo e restituirlo al server usando una pipe di input. In questo semplice esempio, l'origine dati è un buffer allocato dinamicamente di interi lunghi.

Prima che il trasferimento possa iniziare, il client deve impostare puntatori alla variabile di stato, alla routine pull e alla procedura di allocazione. Questi puntatori vengono mantenuti nella variabile pipe dichiarata dal client. In questo caso, SendLongs dichiara inPipe. È possibile usare qualsiasi tipo di dati appropriato per la variabile di stato.

I client avviano i trasferimenti di dati attraverso una pipe richiamando una procedura remota nel server. La chiamata alla procedura remota indica al programma server che il client è pronto per la trasmissione. Il server può quindi eseguire il pull dei dati su se stesso. In questo esempio viene richiamata una procedura remota denominata InPipe. Dopo il trasferimento dei dati al server, la funzione SendLongs libera il buffer allocato in modo dinamico.

Anziché allocare memoria ogni volta che è necessario un buffer. La procedura di allocazione in questo esempio imposta semplicemente un puntatore alla variabile globalBuffer. La procedura pull riutilizza questo buffer ogni volta che trasferisce i dati. È possibile che i programmi client più complessi debbano allocare un nuovo buffer ogni volta che il server esegue il pull dei dati dal client.

Lo stub client chiama la routine pull. La routine pull in questo esempio usa la variabile di stato per tenere traccia della posizione successiva nel buffer dell'origine dati globale da cui eseguire la lettura. Legge i dati dal buffer di origine nel buffer della pipe. Lo stub client trasmette i dati al server. Quando tutti i dati sono stati inviati, la routine pull imposta le dimensioni del buffer su zero. Indica al server di interrompere il pull dei dati.

Tubo

/Oi