管道(PIPE)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机.一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读出来.管道分为两种:匿名管道和命名管道.匿名管道是在父进程和子进程间单向传输数据的一种未命名管道,只能在本地计算机中使用,而不能用于网络间的通信.
匿名通道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:读句柄和写句柄.其原型如下:
BOOL CreatePipe(
PHANDLE hReadPipe, //指向读句柄的指针
PHANDLE hWritePipe, //指向写句柄的指针
LPSECURITY_ATTRIBUTES lpPipeAttributes, //指向安全属性的指针
DWORD nSize //管道大小,若为0则由系统决定
};
匿名管道不支持异步读写操作.
命名管道是在管道是在管道服务器和一台或多台管道客户机之间进行单向或双向通信的一种命名的管道.一个命名管道的所有实例共享同一个管道名,但是每一个实例均拥有独立的缓存和句柄,并且为客户-服务通信提供一个分离的管道.
命名管道可以在同一台计算机的不同进程之间或在跨越一个网络的不同计算机的不同进程间进行有连接的可靠数据通信,如果连接中断,连接双方都能立即收到连接断开的信息。
每一个命名管道都有一个唯一的名字,以区分存在于系统的命名对象列表中的其他命名管道.管道服务器在调用CreateNamedPipe()函数创建命名管道的一个或多个实例时为其指定了名称.对于管道客户机,则是在调用CreateFile()或CallNamedPipe()函数以连接一个命名管道实例时对管道名进行指定.命名管道对其标识采用UNC格式:
\\Server\\Pipe\[Path]Name
其中,第一部分\\Server指定了服务器的名字,命名管道服务就在此服务器创建,其字串部分可以为一个小数点(表示本机)、星号(当前网络字段)、域名或是一个真正的服务;第二部分是一个不可变化的的硬编码字串;第三部分\[Path]Name则使应用程序可以唯一定义及标识一个命名管道的名字,而且可以设置多级目录.
管道服务器首次调用CreateNamedPipe()函数时,使用nMaxInstance参数指定了能同时存在的管道实例的最大数目.服务器可以重复调用CreateNamedPipe()函数去创建管道新的实例,直至达到设定的最大实例数.下面给出CreateNamedPipe()的函数原型:
HANDLE CreateNamedPipe(
LPCTSTR lpName, //指向管道名称的指针
DWORD dwOpenMode, //管道打开模式
DWORD dwPipeMode, //管道模式
DWORD nMaxInstance, //最大实例数
DWORD nOutBufferSize, //输出缓存大小
DWORD nInBufferSize, //输入缓存大小
DWORD nDefaultTimeOut, //超时设置
LPSECURITY_ATTRIBUTES lpSecurityAttributes //安全属性指针
};
其中,dwOpenMode参数用来指示管道在创建好之后,它的传输方向、I/O控制以及安全模式。
命名管道:可用于网络通信;可通过名称引用;支持多客户端连接;支持双向通信;支持异步重叠I/O;
匿名管道:只能本地使用。
公共头文件 PipeDef.h
#ifndef _PIPEDEF_H_
#define _PIPEDEF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <windows.h>
#define MAX_PIPESIZE 1024
#define NAMED_PIPE_CONNECT_EVENT "SRV_CONNECT_EVENT"
#define NAMED_PIPE_WRITE_EVENT "SRV_WRITE_EVENT"
#define NAMED_PIPE_READ_EVENT "SRV_READ_EVENT"
#define CLT_NAMED_PIPE_WRITE_EVENT "CLT_WRITE_EVENT"
#define CLT_NAMED_PIPE_READ_EVENT "CLT_READ_EVENT"
#define SHARED_NAMED_PIPE \\\\.\\pipe\\SHARED_NAMED_PIPE
typedef struct _mgrruntime
{
HANDLE hPipe;
BYTE bRequest[MAX_PIPESIZE];
DWORD dwByteRead;
DWORD dwByteToWrite;
OVERLAPPED oOverlapWrite;
OVERLAPPED oOverlapRead;
}MGRRUNTIME;
typedef struct _svrruntime
{
HANDLE hPipe;
OVERLAPPED oOverlapConnect;
OVERLAPPED oOverlapWrite;
OVERLAPPED oOverlapRead;
DWORD dwByteRead;
BYTE bRequest[MAX_PIPESIZE];
DWORD dwByteToWrite;
BYTE bReply[MAX_PIPESIZE];
BOOL fPendingIO;
BOOL fConnected;
}SVRRUNTIME;
#ifdef __cplusplus
}
#endif
#endif
NamedPipeServer.cpp
#include <iostream>
#include "PipeDef.h"
#include <process.h>
using std::cout;
using std::endl;
static BOOL InitRuntime(SVRRUNTIME* runtime);
static void CleanupRuntime(SVRRUNTIME* runtime);
static void Reconnect(SVRRUNTIME* runtime);
static BOOL ConnectToNewClient(HANDLE hPipe);
static BOOL CheckPipeStatus(HANDLE hPipe, OVERLAPPED *pOverLap);
static BOOL ReadFromPipe(SVRRUNTIME* runtime);
static BOOL WriteToPipe(SVRRUNTIME* runtime);
unsigned __stdcall SvrThread(void* );
int main()
{
unsigned id;
SVRRUNTIME runtime;
InitRuntime(&runtime);
Sleep(4000);
HANDLE hThread = (HANDLE)_beginthreadex(
NULL,
8192,
SvrThread,
(void *)&runtime,
CREATE_SUSPENDED,
&id);
if ((HANDLE)-1 == hThread)
{
cout << "create server thread error" << endl;
return -1;
}
ResumeThread(hThread);
Sleep(10000);
CloseHandle(hThread);
hThread = NULL;
return 0;
}
unsigned __stdcall SvrThread(void* param)
{
SVRRUNTIME *rt = (SVRRUNTIME *)param;
cout << "in thread..........." << endl;
staticint i = 0;
for (;;)
{
if (ConnectToNewClient(rt->hPipe))
{
if (!WriteToPipe(rt))
{
cout << "write msg to pipe error." << endl;
break;
}
else
cout << "write msg to pipe successfully" << endl;
Sleep(1000);
ReadFromPipe(rt);
}
else
{
++i;
Sleep(1000);
if (i > 10)
break;
}
}
return 0;
}
BOOL InitRuntime(SVRRUNTIME* runtime)
{
BOOL ret = FALSE;
memset(runtime, 0, sizeof(SVRRUNTIME));
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
do{
runtime->fConnected = FALSE;
runtime->oOverlapConnect.hEvent = CreateEvent(&sa, TRUE, FALSE, NAMED_PIPE_CONNECT_EVENT);
if (NULL == runtime->oOverlapConnect.hEvent)
break;
runtime->oOverlapWrite.hEvent = CreateEvent(&sa, TRUE, FALSE, NAMED_PIPE_WRITE_EVENT);
if (NULL == runtime->oOverlapConnect.hEvent)
break;
runtime->oOverlapRead.hEvent = CreateEvent(&sa, TRUE, FALSE, NAMED_PIPE_READ_EVENT);
if (NULL == runtime->oOverlapRead.hEvent)
break;
runtime->hPipe = CreateNamedPipe(SHARED_NAMED_PIPE,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED|FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
MAX_PIPESIZE,
MAX_PIPESIZE,
NMPWAIT_USE_DEFAULT_WAIT,
&sa);
if (INVALID_HANDLE_VALUE == runtime->hPipe)
break;
ret = TRUE;
}while(FALSE);
if (!ret)
cout << "init runtime error: " << GetLastError() << endl;
return ret;
}
static void CleanupRuntime(SVRRUNTIME* runtime)
{
if (INVALID_HANDLE_VALUE != runtime->hPipe)
{
FlushFileBuffers(runtime->hPipe);
DisconnectNamedPipe(runtime->hPipe);
CloseHandle(runtime->hPipe);
runtime->hPipe = INVALID_HANDLE_VALUE;
}
if (NULL != runtime->oOverlapConnect.hEvent)
CloseHandle(runtime->oOverlapConnect.hEvent);
if (NULL != runtime->oOverlapWrite.hEvent)
CloseHandle(runtime->oOverlapWrite.hEvent);
if (NULL != runtime->oOverlapRead.hEvent)
CloseHandle(runtime->oOverlapRead.hEvent);
}
static void Reconnect(SVRRUNTIME* runtime)
{
DisconnectNamedPipe(runtime->hPipe);
runtime->fPendingIO = ConnectToNewClient(runtime->hPipe);
runtime->fConnected = runtime->fPendingIO ? FALSE : TRUE;
}
static BOOL ConnectToNewClient(HANDLE hPipe)
{
BOOL bConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (bConnected)
cout << "connect named pipe successfully" << endl;
else
cout << "connect named pipe failed:" << GetLastError() <<endl;
return bConnected;
}
static BOOL CheckPipeStatus(HANDLE hPipe, OVERLAPPED *pOverLap)
{
BOOL bSuc = TRUE;
DWORD dwBytes = 0;
bSuc = GetOverlappedResult(hPipe, pOverLap, &dwBytes, FALSE);
return bSuc;
}
static BOOL ReadFromPipe(SVRRUNTIME* runtime)
{
BOOL bSuc = FALSE;
DWORD dwBytes = 0;
DWORD dwErr = 0;
if (CheckPipeStatus(runtime->hPipe, &(runtime->oOverlapRead)))
{
for (;;)
{
bSuc = TRUE;
while (bSuc)
{
runtime->fPendingIO = FALSE;
runtime->dwByteRead = 0;
memset(runtime->bRequest, 0, sizeof(runtime->bRequest));
bSuc = ReadFile(runtime->hPipe,
runtime->bRequest,
sizeof(runtime->bRequest),
&runtime->dwByteRead,
&runtime->oOverlapRead);
if (bSuc && runtime->dwByteRead != 0)
{
cout << "server receives client's call as the following..." << endl;
for (int i = 0; i < runtime->dwByteRead; ++i)
cout << runtime->bRequest[i];
cout << endl;
ResetEvent(runtime->oOverlapRead.hEvent);
}
};
dwErr = GetLastError();
if (!bSuc && (dwErr == ERROR_IO_PENDING))
runtime->fPendingIO = TRUE;
Reconnect(runtime);
break;
}
}
return bSuc;
}
static BOOL WriteToPipe(SVRRUNTIME* runtime)
{
BOOL bSuc = FALSE;
DWORD dwErr;
DWORD dwByteWritten;
char msg[] ="server reply to client: hi...";
sprintf((char *)runtime->bReply,"%s", msg);
runtime->dwByteToWrite = sizeof(msg);
for (;;)
{
runtime->fPendingIO = FALSE;
bSuc = WriteFile(runtime->hPipe,
runtime->bReply,
runtime->dwByteToWrite,
&dwByteWritten,
&runtime->oOverlapWrite);
if (!bSuc)
{
cout << "write fail..." << GetLastError() <<endl;
dwErr = GetLastError();
if (ERROR_IO_PENDING == dwErr)
{
bSuc = GetOverlappedResult(runtime->hPipe, &runtime->oOverlapWrite, &dwByteWritten, TRUE);
if (!bSuc)
CancelIo(runtime->hPipe);
}
else
Reconnect(runtime);
}
ResetEvent(runtime->oOverlapWrite.hEvent);
break;
}
return bSuc;
}
NamedPipeClient.cpp
#include <iostream>
#include "PipeDef.h"
using std::cout;
using std::endl;
static BOOL InitPipe(CLTRUNTIME *runtime);
static void CleanupPipe(CLTRUNTIME* runtime);
static BOOL CheckPipeStatus(HANDLE hPipe, OVERLAPPED *pOverLap);
static BOOL ReadFromPipe(CLTRUNTIME *runtime);
static BOOL WriteToPipe(CLTRUNTIME *runtime);
int main()
{
CLTRUNTIME runtime;
InitPipe(&runtime);
int i = 0;
for (; i < 10; ++i)
{
ReadFromPipe(&runtime);
Sleep(1000);
WriteToPipe(&runtime);
}
Sleep(30000);
CleanupPipe(&runtime);
return 0;
}
static BOOL InitPipe(CLTRUNTIME *runtime)
{
BOOL bRet = FALSE;
memset(runtime, 0, sizeof(CLTRUNTIME));
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
for (;;)
{
runtime->oOverlapRead.hEvent = CreateEvent(&sa, TRUE, FALSE, CLT_NAMED_PIPE_READ_EVENT);
if (NULL == runtime->oOverlapRead.hEvent)
break;
runtime->oOverlapWrite.hEvent = CreateEvent(&sa, TRUE, FALSE, CLT_NAMED_PIPE_WRITE_EVENT);
if (NULL == runtime->oOverlapWrite.hEvent)
break;
runtime->hPipe = CreateFile(SHARED_NAMED_PIPE,
GENERIC_ALL,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE != runtime->hPipe)
break;
if (ERROR_PIPE_BUSY == GetLastError())
{
cout << "pipe is busy." << endl;
if(!WaitNamedPipe(SHARED_NAMED_PIPE, 1000))
cout << "wait timeout error." << endl;
}
bRet = TRUE;
}
cout << "client open pipe successfully." << endl;
return bRet;
}
static void CleanupPipe(CLTRUNTIME* runtime)
{
if (INVALID_HANDLE_VALUE != runtime->hPipe)
{
CloseHandle(runtime->hPipe);
runtime->hPipe = INVALID_HANDLE_VALUE;
}
}
static BOOL CheckPipeStatus(HANDLE hPipe, OVERLAPPED *pOverLap)
{
BOOL bSuc = TRUE;
DWORD dwBytes = 0;
bSuc = GetOverlappedResult(hPipe, pOverLap, &dwBytes, FALSE);
return bSuc;
}
static BOOL ReadFromPipe(CLTRUNTIME *runtime)
{
BOOL bRet = FALSE;
DWORD dwErr = 0;
if (CheckPipeStatus(runtime->hPipe, &(runtime->oOverlapRead)))
{
bRet = TRUE;
while (bRet)
{
runtime->dwByteRead = 0;
memset(runtime->bRequest, 0, sizeof(runtime->bRequest));
bRet = ReadFile(runtime->hPipe,
runtime->bRequest,
sizeof(runtime->bRequest),
&runtime->dwByteRead,
&runtime->oOverlapRead);
if (bRet && runtime->dwByteRead != 0)
{
for (int i = 0; i < runtime->dwByteRead; ++i)
cout << runtime->bRequest[i];
cout << endl;
ResetEvent(runtime->oOverlapRead.hEvent);
}
}
}
return bRet;
}
static BOOL WriteToPipe(CLTRUNTIME *runtime)
{
BOOL bRet = FALSE;
DWORD dwBytesWritten = 0;
DWORD dwErr = 0;
char msg[] ="client send msg to server: Good";
runtime->dwByteToWrite = sizeof(msg);
bRet = WriteFile(runtime->hPipe,
msg,
sizeof(msg),
&dwBytesWritten,
&runtime->oOverlapWrite);
if (!bRet)
{
dwErr = GetLastError();
if (ERROR_IO_PENDING == dwErr)
{
bRet = GetOverlappedResult(runtime->hPipe, &runtime->oOverlapWrite, &dwBytesWritten, TRUE);
if(!bRet)
CancelIo(runtime->hPipe);
}
}
ResetEvent(runtime->oOverlapWrite.hEvent);
return bRet;
}