9、进程通信之命名管道
命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。
命名管道充分利用了Windows NT和Windows 2000内建的安全机制。
将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并在其中可靠地传输数据。
命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(Named Pipe File System,NPFS)”接口,因此,客户机和服务器可利用标准的Win32文件系统函数(例如:ReadFile和WriteFile)来进行数据的收发。
命名管道服务器和客户机的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。
命名管道服务器只能在Windows NT或Windows 2000上创建。
命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式,在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出了一条消息后,它必须作为一条完整的消息读入。
HANDLE CreateNamedPipe()
CreateNamedPipe,创建命名管道,其中第一个参数管道的名称是格式为"\\.\pipe\pipename", 在VC中使用的时候,因涉及到转义符,作为字符串,应使用"\\\\.\\pipe\\pipename",其中pipe不能更改,大小写没有区分
hPipe=CreateNamedPipe("\\\\.\\pipe\\MyPipe",PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);
if(INVALID_HANDLE_VALUE==hPipe)
{
MessageBox("创建命名管道失败!");
CloseHandle(hPipe);
hPipe=NULL;
return;
}
HANDLE hEvent;
hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(!hEvent)
{
MessageBox("创建事件对象失败!");
CloseHandle(hPipe);
hPipe=NULL;
return;
}
OVERLAPPED ovlap;
//这里调用ZeroMemory和上一章的意义是一样的,为了避免ConnectNamedPipe在调用该结构中使用的是一些不可欲知的参数值,防止有影响
ZeroMemory(&ovlap,sizeof(OVERLAPPED));
ovlap.hEvent=hEvent;
说明:等待客户端连接到一个命名管道实例。If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the OVERLAPPED structure
pointed to by lpOverlapped must contain a handle to a manual-reset event object (which the server can create by using the CreateEvent function).
这是为什么上面需要申明一个自动的事件的对象。
The ConnectNamedPipe function enables a named pipe server process to wait for
a client process to connect to an instance of a named pipe.
if(!ConnectNamedPipe(hPipe,&ovlap))
{
if(ERROR_IO_PENDING!=GetLastError())
{
MessageBox("等待客户端的连接失败!");
CloseHandle(hPipe);
CloseHandle(hEvent);
hPipe=NULL;
}
}
//等待事件状态有效,如果当前无效,INFINITE参数表明则一直等待下去
if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE))
{
MessageBox("等待对象失败!");
CloseHandle(hPipe);
CloseHandle(hEvent);
hPipe=NULL;
}
CloseHandle(hEvent); //说明已经有客户端连接到了
命名管道的读写和上一章是类似的,这里就省略掉了
命名管道的客户端实现(核心为命名管道的连接):
//WaitNamePipe的参数NMPWAIT_WAIT_FOREVER一直等待下去,直到等待到可用的连接,当然也可以设置超时的时间,但前提是所有的程序里所有的命名管道的超时时间必须一样
if(!WaitNamedPipe("\\\\.\\pipe\\MyPipe",NMPWAIT_WAIT_FOREVER))
{
MessageBox("当前没有可用的命名管道实例");
return;
}
//打开命名管道,建立连接
hPipe=CreateFile("\\\\127.0.0.1\\pipe\\MyPipe",GENERIC_READ|GENERIC_WRITE, 0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hPipe)
{
MessageBox("打开命名管道失败!");
hPipe=NULL;
}
注意:程序的运行方式为先点击服务端的创建命名管道,然后点击客户端的连接管道,再点击服务端的发送数据,再在客户端点击接收数据。
参考
[1]MSDN
[2]《VC++ 深入》
[3]http://blog.csdn.net/liufei_learning/archive/2009/12/17/5026410.aspx