Implementieren von Ausgabepipes auf dem Client
Wenn Sie eine Ausgabepipe zum Übertragen von Daten vom Server an den Client verwenden, müssen Sie eine Pushprozedur in Ihrem Client implementieren. Die Pushprozedur verwendet einen Zeiger auf einen Puffer und eine Elementanzahl aus dem Clientstub und verarbeitet die Daten, wenn die Elementanzahl größer als 0 ist. Beispielsweise könnte es die Daten aus dem Puffer des Stubs in seinen eigenen Arbeitsspeicher kopieren. Alternativ kann es die Daten im Puffer des Stubs verarbeiten und in einer Datei speichern. Wenn die Elementanzahl gleich 0 ist, schließt die Pushprozedur alle erforderlichen Bereinigungsaufgaben ab, bevor sie zurückgegeben wird.
Im folgenden Beispiel weist die Clientfunktion ReceiveLongs eine Pipestruktur und einen globalen Speicherpuffer zu. Es initialisiert die -Struktur, führt den Remoteprozeduraufruf aus und gibt dann den Arbeitsspeicher frei.
Beispiel
//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
Dieses Beispiel enthält die vom MIDL-Compiler generierte Headerdatei. Weitere Informationen finden Sie unter Definieren von Pipes in der IDL-Datei. Außerdem deklariert sie die Variable globalPipeData, die als Datensenke verwendet wird. Die Variable globalBuffer ist ein Puffer, den die Pushprozedur zum Empfangen von Datenblöcken verwendet, die sie in globalPipeData speichert.
Die ReceiveLongs-Funktion deklariert eine Pipe und reserviert Speicherplatz für die globale Datensenkenvariable. In Ihrem Client/Server-Programm kann die Datensenke eine Datei oder Datenstruktur sein, die der Client erstellt. In diesem einfachen Beispiel ist die Datenquelle ein dynamisch zugeordneter Puffer aus langen ganzen Zahlen.
Bevor die Datenübertragung beginnen kann, muss Ihr Clientprogramm die Ausgabepipestruktur initialisieren. Sie muss Zeiger auf die Zustandsvariable, die Pushprozedur und die Alloc-Prozedur festlegen. In diesem Beispiel wird die Ausgabepipevariable als outputPipe bezeichnet.
Clients signalisieren Servern, dass sie bereit sind, Daten zu empfangen, indem sie eine Remoteprozedur auf dem Server aufrufen. In diesem Beispiel heißt die Remoteprozedur OutPipe. Wenn der Client die Remoteprozedur aufruft, beginnt der Server mit der Datenübertragung. Jedes Mal, wenn Daten eintreffen, ruft der Client-Stub die Zuweisungs- und Pushprozeduren des Clients nach Bedarf auf.
Anstatt bei jedem Benötigten Puffer Arbeitsspeicher zuzuweisen, legt die Zuweisungsprozedur in diesem Beispiel einfach einen Zeiger auf die Variable globalBuffer fest. Die Pullprozedur verwendet diesen Puffer dann bei jeder Datenübertragung wieder. Komplexere Clientprogramme müssen möglicherweise jedes Mal, wenn der Server Daten vom Client abruft, einen neuen Puffer zuweisen.
Die Pushprozedur in diesem Beispiel verwendet die Statusvariable, um die nächste Position nachzuverfolgen, an der Daten im globalen Datensenkenpuffer gespeichert werden. Es schreibt Daten aus dem Pipepuffer in den Senkenpuffer. Der Clientstub empfängt dann den nächsten Datenblock vom Server und speichert ihn im Pipepuffer. Wenn alle Daten gesendet wurden, überträgt der Server einen Puffer der Größe Null. Dadurch wird die Pushprozedur so angezeigt, dass der Empfang von Daten beendet wird.
Zugehörige Themen