命名管道客户端流程

【勇芳软件工作室】汉化HomePreviousNext

客户端进程使用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;

}