Sviluppo del server tramite handle di contesto

Dal punto di vista dello sviluppo del programma server, un handle di contesto è un puntatore non tipizzato. I programmi server inizializzano gli handle del contesto puntandoli ai dati in memoria o su un'altra forma di archiviazione ( ad esempio i file nei dischi).

Si supponga, ad esempio, che un client usi un handle di contesto per richiedere una serie di aggiornamenti a un record in un database. Il client chiama una procedura remota nel server e la passa una chiave di ricerca. Il programma server cerca il database per la chiave di ricerca e ottiene il numero di record intero del record corrispondente. Il server può quindi puntare un puntatore a void in una posizione di memoria contenente il numero di record. Quando restituisce, la procedura remota deve restituire il puntatore come handle di contesto tramite il relativo valore restituito o il relativo elenco di parametri. Il client deve passare il puntatore al server ogni volta che ha chiamato procedure remote per aggiornare il record. Durante ognuna di queste operazioni di aggiornamento, il server esegue il cast del puntatore void come puntatore a un intero.

Dopo che il programma del server punta l'handle di contesto ai dati del contesto, l'handle viene considerato aperto. Gli handle contenenti un valore NULL vengono chiusi. Il server gestisce un handle di contesto aperto fino a quando il client chiama una procedura remota che lo chiude. Se la sessione client termina mentre l'handle è aperto, l'esecuzione RPC chiama la routine di esecuzione del server per liberare l'handle.

Il frammento di codice seguente illustra come un server potrebbe implementare un handle di contesto. In questo esempio il server gestisce un file di dati in cui il client scrive usando le procedure remote. Le informazioni sul contesto sono un handle di file che tiene traccia del percorso corrente nel file in cui il server scriverà i dati. L'handle di file viene pacchetto come handle di contesto nell'elenco dei parametri per le chiamate di routine remote. Una struttura contiene il nome del file e l'handle di file. La definizione dell'interfaccia per questo esempio è illustrata in Sviluppo interfaccia usando handle di contesto.

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

La funzione RemoteOpen apre un file nel server:

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 funzione RemoteRead legge un file nel server.

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 funzione RemoteClose chiude un file nel server. Si noti che l'applicazione server deve assegnare NULL all'handle di contesto come parte della funzione di chiusura. Questo comunica allo stub del server e alla libreria di runtime RPC eliminata dall'handle di contesto. In caso contrario, la connessione verrà mantenuta aperta e alla fine si verificherà un run-down di contesto.

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;
}

Nota

Sebbene sia previsto che il client passi un handle di contesto valido a una chiamata con attributi direzionali [in, out], RPC non rifiuta handle di contesto NULL per questa combinazione di attributi direzionali. L'handle di contesto NULL viene passato al server come puntatore NULL . Il codice del server per le chiamate contenenti un handle di contesto [in, out] deve essere scritto per evitare una violazione di accesso quando viene ricevuto un puntatore NULL .