命名管道事务是将写入操作和读取操作组合到单个网络操作中的客户端 - 服务器通信。事务只能在双工消息类型的管道上使用。事务提高客户端和远程服务器之间网络通信的性能。进程可以使用TransactNamedPipe和CallNamedPipe函数来执行命名管道事务。
TransactNamedPipe通常由客户端进程用于向命名管道服务器写入请求消息并读取服务器的响应消息。客户端进程必须指定GENERIC_READ |当通过调用CreateFile功能打开管道句柄时,通过GENERIC_WRITE访问。然后,客户端进程通过调用SetNamedPipeHandleState函数将管道句柄设置为消息读取模式。如果调用TransactNamedPipe中指定的读取缓冲区不够大,不足以容纳服务器写入的整个消息,函数返回FALSE,并返回ERROR_MORE_DATA。客户端可以通过调用ReadFile,ReadFileEx或PeekNamedPipe 功能来读取消息的其余部分。
TransactNamedPipe通常由客户端进程调用,但也可以由服务器进程使用。
以下示例显示使用TransactNamedPipe的客户端进程。该示例假定客户端进程已使用CreateFile连接到管道和SetNamedPipeHandleState来设置管道句柄的读取模式,如上一节中的客户端进程示例所示。
fSuccess = TransactNamedPipe(
hPipe, //管道手柄
lpszWrite, // size of read buffer
strlen(lpszWrite)+1, //消息长度
chReadBuf, //缓冲区接收回复
512, //读缓冲区大小
&cbRead, //读取的字节数
NULL); //不重叠
//如果发生错误,则退出,除非该错误指示有更多的错误
//消息中的数据。
if (!fSuccess && (GetLastError() != ERROR_MORE_DATA))
MyErrExit("TransactNamedPipe");
而(1)
{
//将数据从管道写入STDOUT。
if(!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE))
chReadBuf,cbRead,& cbWritten,NULL))
break;
//如果TransactNamedPipe或ReadFile成功,则为Break。
如果(fSuccess)
break;
//如果消息中有更多数据,请从管道读取。
fSuccess = ReadFile(
hPipe, //管道手柄
chReadBuf, //缓冲区接收回复
512, //缓冲区大小
&cbRead, //读取的字节数
NULL); //不重叠
//如果出现ERROR_MORE_DATA以外的错误,则退出。
if (! fSuccess && (GetLastError() != ERROR_MORE_DATA))
break;
}
客户端进程使用CallNamedPipe将CreateFile(如有必要),TransactNamedPipe和CloseHandle功能调用到单个呼叫中。由于管道句柄在函数返回之前关闭,如果消息大于读取缓冲区的指定大小,则消息中的任何其他字节都将丢失。以下示例显示了使用CallNamedPipe.
//组合连接,等待,写入,读取和关闭操作。
fSuccess = CallNamedPipe(
lpszPipename, //管道名称
lpszWrite, // size of read buffer
strlen(lpszWrite)+1, //消息长度
chReadBuf, //缓冲区接收回复
512, //读缓冲区大小
&cbRead, //读取的字节数
20000); //等待20秒
if (fSuccess || GetLastError() == ERROR_MORE_DATA)
{
//将数据从管道写入STDOUT。
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
chReadBuf, cbRead, &cbWritten, NULL);
//管道是关闭的,所以没有更多的字节可以从中读取
// 信息。
如果(!fSuccess)
printf("\n...extra data in message was lost\n");
}