windows编程中,如果涉及到本地两个进程之间的通信,最好的方式就是管道,管道支持同步和异步两种模式,作为服务端,当然用异步好,本文章直接提供用IO完成端口实现管道服务端的代码。
// PipeServer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
struct MyOverlapped
{
OVERLAPPED overlapped;
char szBuf[1024];
int iType;
HANDLE hPipe;
};
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\pipename");
DWORD WINAPI ThreadFunc(LPVOID);
HANDLE gPipeInst = INVALID_HANDLE_VALUE;
int main()
{
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
gPipeInst = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // number of instances
0, // output buffer size
0, // input buffer size
NMPWAIT_WAIT_FOREVER, // client time-out
NULL); // default security attributes
CreateIoCompletionPort(gPipeInst, iocp, 10001, 0);
MyOverlapped *overlapped = new MyOverlapped;
memset(overlapped, 0, sizeof(MyOverlapped));
overlapped->iType = 1;
overlapped->hPipe = gPipeInst;
BOOL bRet = ConnectNamedPipe(gPipeInst, (LPOVERLAPPED)overlapped);
DWORD err = ::GetLastError();
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
for (int i = 0; i < 2 * systemInfo.dwNumberOfProcessors; i++)
{
CreateThread(NULL, 0, ThreadFunc, (LPVOID)iocp, 0, NULL);
}
system("pause");
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
HANDLE iocp = (HANDLE)p;
DWORD key = 0;
DWORD dwReaded = 0;
MyOverlapped *overlapped = NULL;
while (1)
{
overlapped = NULL;
BOOL bRet = GetQueuedCompletionStatus(iocp, &dwReaded, &key, (LPOVERLAPPED*)&overlapped, INFINITE);
if (bRet)
{
if (overlapped->iType == 1)
{
说明有客户端连接上来了,此时需要再创建一个管道服务端
HANDLE hPipeInst = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // number of instances
0, // output buffer size
0, // input buffer size
NMPWAIT_WAIT_FOREVER, // client time-out
NULL); // default security attributes
printf("new client connect\n");
HANDLE iocp2 = CreateIoCompletionPort(hPipeInst, iocp, 10001, 0);
MyOverlapped *pMyOverlapped = new MyOverlapped;
memset(pMyOverlapped, 0, sizeof(MyOverlapped));
pMyOverlapped->iType = 1;
pMyOverlapped->hPipe = hPipeInst;
BOOL bRet = ConnectNamedPipe(hPipeInst, (LPOVERLAPPED)pMyOverlapped);
overlapped->iType = 2;
ReadFile(overlapped->hPipe, overlapped->szBuf, 1024, NULL, (LPOVERLAPPED)overlapped);
}
else if (overlapped->iType == 2)
{
char szWriteBuf[1024] = {
0 };
strcpy(szWriteBuf, "hello ");
strcat(szWriteBuf, overlapped->szBuf);
WriteFile(overlapped->hPipe, szWriteBuf, strlen(szWriteBuf) + 1, NULL, NULL);
ReadFile(overlapped->hPipe, overlapped->szBuf, 1024, NULL, (LPOVERLAPPED)overlapped);
DWORD err = GetLastError();
}
}
else
{
DWORD err = GetLastError();
if (ERROR_BROKEN_PIPE == err)
{
CloseHandle(overlapped->hPipe);
printf("CloseHandle\n");
delete overlapped;
}
}
}
return 0;
}
此服务端接收客户端的连接,每当客户端用CreateFile进行连接时,服务端的当前实例就被消耗掉,于是调用CreateNamedPipe创建新的实例,以供客户端连接。
服务端接收到客户端发送的数据后,前面添加hello ,然后返回给客户端。
服务端写数据的时候,直接用同步模式,原因是我觉得是没必要弄成异步模式
客户端的例子也顺带提供下:
// PipeClient.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
int main()
{
DWORD err = ::GetLastError();
char pipenamestr[30] = {
0 };
sprintf(pipenamestr, "\\\\.\\pipe\\pipename");
if (WaitNamedPipe(pipenamestr, NMPWAIT_WAIT_FOREVER) == FALSE)
{
err = ::GetLastError();
}
char szBuf[1024];
std::cout << "please input the buf:";
std::cin >> szBuf;
HANDLE hPipe = CreateFile(_T("\\\\.\\pipe\\pipename"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
WriteFile(hPipe, szBuf, 1024, NULL, NULL);
ReadFile(hPipe, szBuf, sizeof(szBuf), NULL, NULL);
printf("szBuf is %s\n", szBuf);
//CloseHandle(hPipe);
}
while (1);
return 0;
}