Développement de serveur à l’aide de handles de contexte

Du point de vue du développement de programmes serveur, un handle de contexte est un pointeur non typé. Les programmes serveur initialisent les handles de contexte en les pointant vers les données en mémoire ou sur une autre forme de stockage (par exemple, des fichiers sur des disques).

Par instance, supposons qu’un client utilise un handle de contexte pour demander une série de mises à jour d’un enregistrement dans une base de données. Le client appelle une procédure distante sur le serveur et lui passe une clé de recherche. Le programme serveur recherche la clé de recherche dans la base de données et obtient le numéro d’enregistrement entier de l’enregistrement correspondant. Le serveur peut ensuite pointer un pointeur vers void à un emplacement mémoire contenant le numéro d’enregistrement. Lorsqu’elle retourne, la procédure distante doit retourner le pointeur en tant que handle de contexte via sa valeur de retour ou sa liste de paramètres. Le client doit passer le pointeur vers le serveur chaque fois qu’il appelle des procédures distantes pour mettre à jour l’enregistrement. Au cours de chacune de ces opérations de mise à jour, le serveur castait le pointeur void pour qu’il soit un pointeur vers un entier.

Une fois que le programme serveur pointe le handle de contexte sur les données de contexte, le handle est considéré comme ouvert. Les handles contenant une valeur NULL sont fermés. Le serveur conserve un handle de contexte ouvert jusqu’à ce que le client appelle une procédure distante qui le ferme. Si la session cliente se termine alors que le handle est ouvert, l’heure d’exécution RPC appelle la routine d’exécution du serveur pour libérer le handle.

Le fragment de code suivant montre comment un serveur peut implémenter un handle de contexte. Dans cet exemple, le serveur gère un fichier de données dans lequel le client écrit à l’aide de procédures distantes. Les informations de contexte sont un handle de fichier qui effectue le suivi de l’emplacement actuel dans le fichier où le serveur doit écrire des données. Le handle de fichier est empaqueté en tant que handle de contexte dans la liste des paramètres pour les appels de procédure distante. Une structure contient le nom de fichier et le handle de fichier. La définition d’interface de cet exemple est illustrée dans Développement d’interface à l’aide de handles de contexte.

/* cxhndlp.c (fragment of file containing remote procedures) */
typedef struct 
{
     FILE* hFile;
     char   achFile[256];
} FILE_CONTEXT_TYPE;

La fonction RemoteOpen ouvre un fichier sur le serveur :

short RemoteOpen(
    PPCONTEXT_HANDLE_TYPE pphContext,
    unsigned char *pszFileName)
{
    FILE               *hFile;
    FILE_CONTEXT_TYPE  *pFileContext;
 
    if ((hFile = fopen(pszFileName, "r")) == NULL) 
    {
        *pphContext = (PCONTEXT_HANDLE_TYPE) NULL;
        return(-1);
    }
    else 
    {
        pFileContext = (FILE_CONTEXT_TYPE *) 
                       MIDL_user_allocate(sizeof(FILE_CONTEXT_TYPE));
        pFileContext->hFile = hFile;
        // check if pszFileName is longer than 256 and if yes, return
        // an error
        strcpy_s(pFileContext->achFile, srlen(pszFileName), pszFileName);
        *pphContext = (PCONTEXT_HANDLE_TYPE) pFileContext;
        return(0);
    }
}

La fonction RemoteRead lit un fichier sur le serveur.

short RemoteRead(
    PCONTEXT_HANDLE_TYPE phContext, 
    unsigned char *pbBuf, 
    short *pcbBuf) 
{ 
    FILE_CONTEXT_TYPE *pFileContext; 
    printf("in RemoteRead\n"); 
    pFileContext = (FILE_CONTEXT_TYPE *) phContext; 
    *pcbBuf = (short) fread(pbBuf, sizeof(char), 
                            BUFSIZE, 
                            pFileContext->hFile); 
    return(*pcbBuf); 
}

La fonction RemoteClose ferme un fichier sur le serveur. Notez que l’application serveur doit affecter null au handle de contexte dans le cadre de la fonction close. Cela indique au stub du serveur et à la bibliothèque d’exécution RPC que le handle de contexte a été supprimé. Dans le cas contraire, la connexion sera maintenue ouverte et, à terme, une panne de contexte se produira.

void RemoteClose(PPCONTEXT_HANDLE_TYPE pphContext)
{
    FILE_CONTEXT_TYPE *pFileContext;
 
    if (*pphContext == NULL)
    {
        //Log error, client tried to close a NULL handle.
        return;
    }
    pFileContext = (FILE_CONTEXT_TYPE *)*pphContext;
    printf("File %s closed.\n", pFileContext->achFile);
    fclose(pFileConext->hFile);
    MIDL_user_free(pFileContext);
 
    // This tells the run-time, when it is marshalling the out 
    // parameters, that the context handle has been closed normally.
    *pphContext = NULL;
}

Notes

Bien qu’il soit attendu que le client passe un handle de contexte valide à un appel avec des attributs directionnels [in, out], RPC ne rejette pas les handles de contexte NULL pour cette combinaison d’attributs directionnels. Le handle de contexte NULL est passé au serveur en tant que pointeur NULL . Le code serveur pour les appels contenant un handle de contexte [in, out] doit être écrit pour éviter une violation d’accès lors de la réception d’un pointeur NULL .