Condividi tramite


Implementazione delle pipe di output nel client

Quando si usa una pipe di output per trasferire i dati dal server al client, è necessario implementare una procedura push nel client. La procedura push accetta un puntatore a un buffer e un conteggio degli elementi dallo stub del client e, se il conteggio degli elementi è maggiore di 0, elabora i dati. Ad esempio, potrebbe copiare i dati dal buffer dello stub alla propria memoria. In alternativa, potrebbe elaborare i dati nel buffer dello stub e salvarli in un file. Quando il numero di elementi è uguale a zero, la procedura push completa le attività di pulizia necessarie prima di restituire.

Nell'esempio seguente la funzione client ReceiveLongs alloca una struttura pipe e un buffer di memoria globale. Inizializza la struttura, effettua la chiamata alla procedura remota e quindi libera la memoria.

Esempio

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

Questo esempio include il file di intestazione generato dal compilatore MIDL. Per informazioni dettagliate, vedere Definizione di pipe nel file IDL. Dichiara inoltre una variabile globalPipeData che usa come sink di dati. La variabile globalBuffer è un buffer usato dalla routine push per ricevere blocchi di dati archiviati in globalPipeData.

La funzione ReceiveLongs dichiara una pipe e alloca lo spazio di memoria per la variabile sink di dati globale. Nel programma client/server il sink di dati può essere un file o una struttura di dati creata dal client. In questo semplice esempio, l'origine dati è un buffer allocato dinamicamente di interi lunghi.

Prima che il trasferimento dei dati possa iniziare, il programma client deve inizializzare la struttura della pipe di output. Deve impostare puntatori alla variabile di stato, alla routine push e alla routine di allocazione. In questo esempio la variabile della pipe di output è denominata outputPipe.

I client segnalano ai server che sono pronti per ricevere i dati richiamando una procedura remota nel server. In questo esempio la procedura remota è denominata OutPipe. Quando il client chiama la procedura remota, il server avvia il trasferimento dei dati. Ogni volta che arrivano i dati, lo stub client chiama le procedure di allocazione e push del client in base alle esigenze.

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 quindi 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.

La procedura push in questo esempio usa la variabile di stato per tenere traccia della posizione successiva in cui archivierà i dati nel buffer del sink di dati globale. Scrive i dati dal buffer della pipe nel buffer sink. Lo stub client riceve quindi il blocco successivo di dati dal server e lo archivia nel buffer della pipe. Quando tutti i dati sono stati inviati, il server trasmette un buffer di dimensioni zero. In questo modo viene illustrata la procedura push per interrompere la ricezione dei dati.

Tubo

/Oi