使用上下文句柄的服务器开发

从服务器程序开发的角度来看,上下文句柄是非类型化指针。 服务器程序通过将上下文句柄指向内存中的数据或某种其他形式的存储 ((例如磁盘) 上的文件)来初始化上下文句柄。

例如,假设客户端使用上下文句柄对数据库中的记录请求一系列更新。 客户端在服务器上调用远程过程,并为其传递搜索密钥。 服务器程序在数据库中搜索搜索键,并获取匹配记录的整数记录编号。 然后,服务器可以将指针指向包含记录号的内存位置的 void。 返回时,远程过程需要通过其返回值或其参数列表将指针作为上下文句柄返回。 客户端每次调用远程过程以更新记录时,都需要将指针传递到服务器。 在每个更新操作期间,服务器会将 void 指针强制转换为指向整数的指针。

服务器程序将上下文句柄指向上下文数据后,该句柄被视为已打开。 包含 NULL 值的句柄处于关闭状态。 服务器会保留一个打开的上下文句柄,直到客户端调用关闭它的远程过程。 如果客户端会话在句柄打开时终止,RPC 运行时会调用服务器运行例程来释放句柄。

以下代码片段演示了服务器如何实现上下文句柄。 在此示例中,服务器维护客户端使用远程过程写入的数据文件。 上下文信息是一个文件句柄,用于跟踪服务器将写入数据的文件中的当前位置。 文件句柄打包为远程过程调用的参数列表中的上下文句柄。 结构包含文件名和文件句柄。 此示例的接口定义显示在 使用上下文句柄的接口开发中。

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

函数 RemoteOpen 在服务器上打开一个文件:

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

函数 RemoteRead 读取服务器上的文件。

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

RemoteClose 函数关闭服务器上的文件。 请注意,服务器应用程序必须向上下文句柄分配 NULL 作为 close 函数的一部分。 这会与已删除上下文句柄的服务器存根和 RPC 运行时库通信。 否则,连接将保持打开状态,最终会发生上下文关闭。

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

注意

虽然预期客户端会将有效的上下文句柄传递给具有 [in, out] 方向属性的调用,但 RPC 不会拒绝此方向属性组合的 NULL 上下文句柄。 NULL 上下文句柄作为 NULL 指针传递给服务器。 应编写包含 [in, out] 上下文句柄的调用的服务器代码,以避免在收到 NULL 指针时发生访问冲突。