Desenvolvimento de servidor usando identificadores de contexto
Sob a perspetiva do desenvolvimento de software para servidor, um identificador de contexto é um ponteiro sem tipo. Os programas de servidor inicializam identificadores de contexto apontando-os para dados na memória ou em alguma outra forma de armazenamento (como arquivos em discos).
Por exemplo, suponha que um cliente use um identificador de contexto para solicitar uma série de atualizações para um registro em um banco de dados. O cliente chama um procedimento remoto no servidor e passa-lhe uma chave de pesquisa. O programa de servidor procura a chave de pesquisa no banco de dados e obtém o número de registro inteiro do registro correspondente. O servidor pode então apontar um ponteiro para void numa localização de memória que contém o número de registo. Quando ele retorna, o procedimento remoto precisa retornar o ponteiro como um identificador de contexto por meio de seu valor de retorno ou sua lista de parâmetros. O cliente precisaria passar o ponteiro para o servidor cada vez que chamasse procedimentos remotos para atualizar o registro. Durante cada uma dessas operações de atualização, o servidor converteria o ponteiro vazio para ser um ponteiro para um inteiro.
Depois que o programa do servidor aponta o identificador de contexto para os dados de contexto, o identificador é considerado aberto. Os manípulos que contêm um valor de NULL são encerrados. O servidor mantém um identificador de contexto aberto até que o cliente chame um procedimento remoto que o feche. Se a sessão do cliente terminar enquanto o identificador estiver aberto, o tempo de execução da RPC invoca a rotina de encerramento do servidor para liberar o identificador.
O fragmento de código a seguir demonstra como um servidor pode implementar um identificador de contexto. Neste exemplo, o servidor mantém um arquivo de dados no qual o cliente grava usando procedimentos remotos. As informações de contexto são um identificador de arquivo que controla o local atual no arquivo onde o servidor gravará dados. O identificador de arquivo é empacotado como um identificador de contexto na lista de parâmetros para chamadas de procedimento remoto. Uma estrutura contém o nome do arquivo e o identificador de arquivo. A definição de interface para este exemplo é mostrada em Desenvolvimento de Interface Usando Manipulação de Contexto.
/* cxhndlp.c (fragment of file containing remote procedures) */
typedef struct
{
FILE* hFile;
char achFile[256];
} FILE_CONTEXT_TYPE;
A função RemoteOpen abre um arquivo no servidor:
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);
}
}
A função RemoteRead lê um arquivo no servidor.
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);
}
A função RemoteClose fecha um arquivo no servidor. Observe que o aplicativo de servidor deve atribuir NULL ao identificador de contexto como parte da função close. Isso comunica ao stub do servidor e à biblioteca de tempo de execução RPC que o identificador de contexto foi excluído. Caso contrário, a conexão será mantida aberta e, eventualmente, ocorrerá um esgotamento de contexto.
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;
}
Observação
Embora se espere que o cliente passe um identificador de contexto válido para uma chamada com atributos direcionais [in, out], o RPC não rejeita identificadores de contexto NULL para essa combinação de atributos direcionais. O identificador de contexto NULL é passado para o servidor como um ponteiro NULL . O código do servidor para chamadas que contêm um identificador de contexto [in, out] deve ser gravado para evitar uma violação de acesso quando um ponteiro NULL é recebido.