用IO完成端口实现管道异步服务端

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;
}


おすすめ

転載: blog.csdn.net/tusong86/article/details/113796593