Implémentation de canaux d’entrée sur le client
Lorsque vous utilisez un canal d’entrée pour transférer des données du client vers le serveur, vous devez implémenter une procédure d’extraction. La procédure de tirage doit rechercher les données à transférer, lire les données dans la mémoire tampon et définir le nombre d’éléments à envoyer. Toutes les données ne doivent pas se trouver dans la mémoire tampon lorsque le serveur commence à extraire des données vers lui-même. La procédure de tirage peut remplir la mémoire tampon de manière incrémentielle.
Lorsqu’il n’y a plus de données à envoyer, la procédure définit son dernier argument sur zéro. Lorsque toutes les données sont envoyées, la procédure d’extraction doit effectuer le nettoyage nécessaire avant de retourner. Pour un paramètre qui est un canal [in, out], la procédure d’extraction doit réinitialiser la variable d’état du client une fois que toutes les données ont été transmises, afin que la procédure push puisse les utiliser pour recevoir des données.
L’exemple suivant est extrait du programme Pipedemo inclus avec le Kit de développement logiciel (SDK) de plateforme.
//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
Cet exemple inclut le fichier d’en-tête généré par le compilateur MIDL. Pour plus d’informations, consultez Définition de canaux dans des fichiers IDL. Il déclare également une variable qu’il utilise comme source de données appelée globalPipeData. La variable globalBuffer est une mémoire tampon que la procédure de tirage utilise pour envoyer les blocs de données qu’elle obtient à partir de globalPipeData.
La fonction SendLongs déclare le canal d’entrée et alloue de la mémoire pour la variable de source de données globalPipeData. Dans votre programme client/serveur, la source de données peut être un fichier ou une structure que le client crée. Vous pouvez également demander à votre programme client d’obtenir des données à partir du serveur, de les traiter et de les renvoyer au serveur à l’aide d’un canal d’entrée. Dans cet exemple simple, la source de données est une mémoire tampon allouée dynamiquement d’entiers longs.
Avant que le transfert puisse commencer, le client doit définir des pointeurs vers la variable d’état, la procédure de tirage et la procédure alloc. Ces pointeurs sont conservés dans la variable de canal déclarée par le client. Dans ce cas, SendLongs déclare inPipe. Vous pouvez utiliser n’importe quel type de données approprié pour votre variable d’état.
Les clients initient des transferts de données sur un canal en appelant une procédure distante sur le serveur. L’appel de la procédure distante indique au programme serveur que le client est prêt à transmettre. Le serveur peut ensuite extraire les données vers lui-même. Cet exemple appelle une procédure distante appelée InPipe. Une fois les données transférées vers le serveur, la fonction SendLongs libère la mémoire tampon allouée dynamiquement.
Au lieu d’allouer de la mémoire chaque fois qu’une mémoire tampon est nécessaire. la procédure alloc dans cet exemple définit simplement un pointeur vers la variable globalBuffer. La procédure d’extraction réutilise cette mémoire tampon chaque fois qu’elle transfère des données. Les programmes clients plus complexes peuvent avoir besoin d’allouer une nouvelle mémoire tampon chaque fois que le serveur extrait des données du client.
Le stub client appelle la procédure de tirage. La procédure de tirage de cet exemple utilise la variable d’état pour suivre la position suivante dans la mémoire tampon de source de données globale à partir de laquelle lire. Il lit les données de la mémoire tampon source dans la mémoire tampon du canal. Le stub client transmet les données au serveur. Une fois toutes les données envoyées, la procédure d’extraction définit la taille de la mémoire tampon sur zéro. Cela indique au serveur d’arrêter l’extraction des données.