客户端进程使用CreateFile函数打开命名管道的句柄。如果管道存在但其所有实例都忙,CreateFile返回FALSE,并且GetLastError函数返回ERROR_PIPE_BUSY。当这种情况发生时,客户端进程使用WaitNamedPipe函数来等待管道的一个实例可用。
如果指定的访问与服务器创建管道所指定的访问(双工,出站或入站)不兼容,CreateFile将失败。对于双工管道(读/写),客户端可以指定读,写或读/写访问;对于出站管道(仅服务器写入),客户端必须指定只读;对于入站管道(只读服务器),客户端必须指定只写。
由CreateFile返回的句柄默认为字节读取模式,阻塞等待模式,禁止重叠模式,禁用直写模式。客户端进程可以使用CreateFile通过指定FILE_FLAG_OVERLAPPED来启用重叠模式,或者通过指定FILE_FLAG_WRITE_THROUGH来启用直写模式。客户端可以使用SetNamedPipeHandleState功能通过指定PIPE_WAIT来启用非阻塞模式,或者通过指定PIPE_READMODE_MESSAGE来启用消息读取模式。
以下示例显示打开命名管道的客户端进程,将管道句柄设置为消息读取模式,使用WriteFile向服务器发送请求,并使用ReadFile读取服务器的回复。该客户端进程可以与上一节中显示的任何消息类型服务器一起使用。但是,使用字节型服务器,当客户端调用SetNamedPipeHandleState更改为消息读取模式时,此客户端进程将失败。因为客户端在消息读取模式下从管道读取,所以ReadFile操作在读取部分消息后可以返回FALSE。当消息大于读取缓冲区时,会发生这种情况。在这种情况下,GetLastError返回ERROR_MORE_DATA,并且通过对ReadFile的其他调用读取消息的其余部分。
#include < windows.h >
DWORD main(int argc,char * argv [])
{
HANDLE hPipe;
LPVOID lpvMessage;
CHAR chBuf[512];
BOOL fSuccess;
DWORD cbRead, cbWritten, dwMode;
LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";
//尝试打开命名管道;如有必要,等待。
而(1)
{
hPipe = CreateFile(
lpszPipename, //管道名称
GENERIC_READ | //读写访问
GENERIC_WRITE,
0, //不分享
NULL, //没有安全属性
OPEN_EXISTING, //打开现有的管道
0, //默认属性
NULL); //没有模板文件
//如果管道手柄有效,则中断。
if (hPipe != INVALID_HANDLE_VALUE)
break;
//如果出现ERROR_PIPE_BUSY以外的错误,则退出。
if (GetLastError() != ERROR_PIPE_BUSY)
MyErrExit("Could not open pipe");
//所有管道实例都忙,所以等待20秒。
如果(!WaitNamedPipe(lpszPipename,20000))ha
MyErrExit("Could not open pipe");
}
//连接管道更改为消息读取模式。
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
hPipe, //管道手柄
&dwMode, //新的管道模式
NULL, //不设置最大字节
NULL); //不设置最大时间
如果(!fSuccess)
MyErrExit("SetNamedPipeHandleState");
//发送消息到管道服务器。
lpvMessage = (argc > 1) ? argv[1] : "default message";
fSuccess = WriteFile(
hPipe, //管道手柄
lpvMessage, // 信息
strlen(lpvMessage) + 1, //消息长度
&cbWritten, //写入字节
NULL); //不重叠
如果(!fSuccess)
MyErrExit("WriteFile");
do
{
//从管道读取。
fSuccess = ReadFile(
hPipe, //管道手柄
chBuf, //缓冲区接收回复
512, //缓冲区大小
&cbRead, //读取的字节数
NULL); //不重叠
if (! fSuccess && GetLastError() != ERROR_MORE_DATA)
break;
//从管道的回复被写入STDOUT。
if(!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE))
chBuf,cbRead,& cbWritten,NULL))
break;
} while (! fSuccess); // repeat loop if ERROR_MORE_DATA
CloseHandle(hPipe);
return 0;
}