Implémentation de canaux de sortie sur le client
Lorsque vous utilisez un canal de sortie pour transférer des données du serveur vers le client, vous devez implémenter une procédure Push dans votre client. La procédure push prend un pointeur vers une mémoire tampon et un nombre d’éléments à partir du stub client et, si le nombre d’éléments est supérieur à 0, traite les données. Par exemple, il peut copier les données de la mémoire tampon du stub vers sa propre mémoire. Elle peut également traiter les données dans la mémoire tampon du stub et les enregistrer dans un fichier. Lorsque le nombre d’éléments est égal à zéro, la procédure push effectue toutes les tâches de nettoyage nécessaires avant de retourner.
Dans l’exemple suivant, la fonction cliente ReceiveLongs alloue une structure de canal et une mémoire tampon globale. Il initialise la structure, effectue l’appel de la procédure distante, puis libère la mémoire.
Exemple
//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
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 un fichier IDL. Elle déclare également une variable, globalPipeData, qu’elle utilise comme récepteur de données. La variable globalBuffer est une mémoire tampon que la procédure push utilise pour recevoir des blocs de données qu’elle stocke dans globalPipeData.
La fonction ReceiveLongs déclare un canal et alloue de l’espace mémoire pour la variable de récepteur de données globale. Dans votre programme client/serveur, le récepteur de données peut être un fichier ou une structure de données que le client cré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 de données puisse commencer, votre programme client doit initialiser la structure du canal de sortie. Il doit définir des pointeurs vers la variable d’état, la procédure push et la procédure alloc. Dans cet exemple, la variable de canal de sortie est appelée outputPipe.
Les clients signalent aux serveurs qu’ils sont prêts à recevoir des données en appelant une procédure distante sur le serveur. Dans cet exemple, la procédure distante est appelée OutPipe. Lorsque le client appelle la procédure distante, le serveur commence le transfert de données. Chaque fois que les données arrivent, le stub client appelle les procédures d’allocation et d’envoi (push) du client en fonction des besoins.
Au lieu d’allouer de la mémoire chaque fois qu’une mémoire tampon est nécessaire, la procédure alloc de cet exemple définit simplement un pointeur vers la variable globalBuffer. La procédure d’extraction réutilise ensuite 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.
La procédure push de cet exemple utilise la variable d’état pour suivre la position suivante où elle stockera les données dans la mémoire tampon globale du récepteur de données. Il écrit les données de la mémoire tampon de canal dans la mémoire tampon du récepteur. Le stub client reçoit ensuite le bloc de données suivant du serveur et le stocke dans la mémoire tampon du canal. Lorsque toutes les données ont été envoyées, le serveur transmet une mémoire tampon de taille nulle. Cela indique que la procédure push cesse de recevoir des données.
Rubriques connexes