29-进程间通信:命名管道

进程间通信:命名管道

命名管道于Socket 相似,能够支持网络之间不同进程的通信

命名管道使用的顺序为:

1.服务端创建命名管道

2.服务端阻塞客户端连接命名管道,并获取句柄

3.客户端连接命名管道

4.客户端根据命名管道名字获取句柄

5.双方根据句柄互相通信

1.服务端创建命名管道函数

HANDLE CreateNamedPipeA(
LPCSTR lpName, // 管道名称
//使用LPCTSTR szNamedPipeName = TEXT("\\\\.\\pipe\\mypipe")传入
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

2.服务端等待客户端连接命名管道函数

BOOL ConnectNamedPipe(
HANDLE hNamedPipe, //管道句柄
LPOVERLAPPED lpOverlapped
);

3.客户端阻塞检测命名管道是否存在函数

该函数仅检测管道是否存在,不获取管道的句柄

WaitNamedPipe(
szNamedPipeName, //管道名
NMPWAIT_WAIT_FOREVER
)

4.客户端获取管道句柄

当检测到该命名管道存在后,将其当作一个文件,获取句柄

CreateFile(szNamedPipeName, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

案例

1.服务端
void CChildView::OnCreateNamedPipe()				//创建命名管道按钮		
{
//1 创建一个命名管道
LPCTSTR szPipeName = TEXT("\\\\.\\pipe\\mypipe");
hNamedPipe = CreateNamedPipe(szPipeName,PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE("CreateNamedhPipe failed with %d\n", GetLastError());
MessageBox(_T("创建命名管道失败"));
return;
}
// 2 等待客户端的连接
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == hEvent)
{
MessageBox(_T("创建事件失败"));
CloseHandle(hNamedPipe);
hNamedPipe = NULL;
return;
}
OVERLAPPED ovlap;
ZeroMemory(&ovlap, sizeof(OVERLAPPED));
ovlap.hEvent = hEvent;
//等待连接
if (!ConnectNamedPipe(hNamedPipe, &ovlap))
{
if (ERROR_IO_PENDING != GetLastError())
{
MessageBox(_T("等待客户端连接失败"));
CloseHandle(hNamedPipe);
CloseHandle(hEvent);
hNamedPipe = NULL;
hEvent = NULL;
return;
}
}
if (WaitForSingleObject(hEvent,INFINITE) == WAIT_FAILED)
{
MessageBox(_T("等待对象失败"));
CloseHandle(hNamedPipe);
CloseHandle(hEvent);
hNamedPipe = NULL;
hEvent = NULL;
return;
}
}

void CChildView::OnSreadNamedPipe() //读取命名管道按钮
{
char szBuf[100] = { 0 };
DWORD dwRead;
if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
}
MessageBox((CStringW)szBuf);
}

void CChildView::OnSwriteNamedpipe() //写入命名管道按钮
{
//写入数据
char szBuf[] = "OnNamedPipe Server";
DWORD dwWrite;
if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
return;
}
}
2.客户端
void CChildView::OnConnectNamedPipe()				//连接命名管道的按钮
{
LPCTSTR szNamedPipeName = TEXT("\\\\.\\pipe\\mypipe");
if (0 == WaitNamedPipe(szNamedPipeName, NMPWAIT_WAIT_FOREVER))
{
MessageBox(_T("当前没有可以利用的管道"));
return;
}
hNamedPipe =
CreateFile(szNamedPipeName, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE("CreateFile failed with %d\n", GetLastError());
MessageBox(_T("打开命名管道失败!"));
hNamedPipe = NULL;
return;
}
}
void CChildView::OnReadNamedPipe() //读取命名管道按钮
{
char szBuf[100] = { 0 };
DWORD dwRead;
if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
}
MessageBox((CStringW)szBuf);
}
void CChildView::OnWriteNamedPipe() //写入命名管道按钮
{
char szBuf[] = "NAMEDPIPE CLIENT";
DWORD dwWrite;
if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
CloseHandle(hWriteCliPipe);
return;
}
CloseHandle(hWriteCliPipe);
}