Implementieren von Eingabepipes auf dem Client

Wenn Sie eine Eingabepipe zum Übertragen von Daten vom Client an den Server verwenden, müssen Sie eine Pullprozedur implementieren. Die Pullprozedur muss die zu übertragenden Daten finden, die Daten in den Puffer lesen und die Anzahl der zu sendenden Elemente festlegen. Nicht alle Daten müssen sich im Puffer befinden, wenn der Server beginnt, Daten auf sich selbst zu pullen. Die Pullprozedur kann den Puffer inkrementell füllen.

Wenn keine weiteren Daten gesendet werden, legt die Prozedur ihr letztes Argument auf 0 (null) fest. Wenn alle Daten gesendet werden, sollte die Pullprozedur vor der Rückgabe alle erforderlichen Bereinigungen durchführen. Bei einem Parameter, bei dem es sich um eine [in, out]-Pipe handelt, muss die Pullprozedur die Statusvariable des Clients zurücksetzen, nachdem alle Daten übertragen wurden, damit die Pushprozedur sie zum Empfangen von Daten verwenden kann.

Das folgende Beispiel wird aus dem Pipedemo-Programm extrahiert, das im Platform Software Development Kit (SDK) enthalten ist.

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

Dieses Beispiel enthält die vom MIDL-Compiler generierte Headerdatei. Weitere Informationen finden Sie unter Definieren von Pipes in IDL-Dateien. Außerdem wird eine Variable deklariert, die als Datenquelle namens globalPipeData verwendet wird. Die Variable globalBuffer ist ein Puffer, den die Pullprozedur zum Senden der Datenblöcke verwendet, die sie aus globalPipeData abruft.

Die SendLongs-Funktion deklariert die Eingabepipe und reserviert Arbeitsspeicher für die Datenquellenvariable globalPipeData. In Ihrem Client-/Serverprogramm kann die Datenquelle eine Datei oder Struktur sein, die vom Client erstellt wird. Sie können auch festlegen, dass Ihr Clientprogramm Daten vom Server abruft, verarbeitet und mithilfe einer Eingabepipe an den Server zurückgibt. In diesem einfachen Beispiel ist die Datenquelle ein dynamisch zugeordneter Puffer aus langen ganzen Zahlen.

Bevor die Übertragung beginnen kann, muss der Client Zeiger auf die Zustandsvariable, die Pullprozedur und die Zuweisungsprozedur festlegen. Diese Zeiger werden in der Pipevariablen beibehalten, die der Client deklariert. In diesem Fall deklariert SendLongs inPipe. Sie können einen beliebigen geeigneten Datentyp für Ihre Zustandsvariable verwenden.

Clients initiieren Datenübertragungen über eine Pipe, indem sie eine Remoteprozedur auf dem Server aufrufen. Durch Aufrufen der Remoteprozedur wird dem Serverprogramm mitgeteilt, dass der Client für die Übertragung bereit ist. Der Server kann dann die Daten auf sich selbst übertragen. In diesem Beispiel wird eine Remoteprozedur namens InPipe aufgerufen. Nachdem die Daten auf den Server übertragen wurden, gibt die SendLongs-Funktion den dynamisch zugeordneten Puffer frei.

Anstatt bei jedem Benötigten Puffer Arbeitsspeicher zuzuweisen. Die Alloc-Prozedur in diesem Beispiel legt einfach einen Zeiger auf die Variable globalBuffer fest. Die Pullprozedur verwendet diesen Puffer bei jeder Datenübertragung wieder. Komplexere Clientprogramme müssen möglicherweise jedes Mal, wenn der Server Daten vom Client abruft, einen neuen Puffer zuweisen.

Der Clientstub ruft die Pullprozedur auf. Die Pullprozedur in diesem Beispiel verwendet die Zustandsvariable, um die nächste Position im globalen Datenquellenpuffer nachzuverfolgen, aus dem gelesen werden soll. Es liest Daten aus dem Quellpuffer in den Pipepuffer. Der Clientstub überträgt die Daten an den Server. Wenn alle Daten gesendet wurden, legt die Pullprozedur die Puffergröße auf Null fest. Dadurch wird der Server aufgefordert, das Pullen von Daten zu beenden.

Rohr

/Oi