1. 程式人生 > >管道的使用---參見Windows核心程式設計

管道的使用---參見Windows核心程式設計

   管道也是一種重要的程序間通訊方式,最近看了Windows核心程式設計裡面關於管道的理論及例子,覺得挺有意思,自己模擬著寫了一個,其中有些還是不太明白
尤其是服務端中的WaitForSingleObjectEx函式的返回值---WAIT-IO-COMPLETION,歡迎大家指點;
測試時,可將編譯的程式複製一份,一個做客戶端,一個做服務端就可以,若要退出就在客戶端直接發出“quit",即可。


程式碼如下:

// ProcessCommunicate.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <windows.h>

#define TEST_PIPE_NAME TEXT("\\\\.\\pipe\\MY_TEST_PIPE")
//#define TEST_EVENT_NAME TEXT("Global\\EVENT_TEST_NAME")
BOOL g_bExit = FALSE;

struct OVERLAPPEDX
{
	OVERLAPPED ov;
	TCHAR buf[1024];
	HANDLE hPipe;
};

void WINAPI CompleteReadRoutine(DWORD dwCode, DWORD dwBytesTrans, LPOVERLAPPED pOv);
void WINAPI CompleteWriteRoutine(DWORD dwCode, DWORD dwBytesTrans, LPOVERLAPPED pOv);

void FreeOverLappedX(OVERLAPPEDX** ppOv)
{
	if (ppOv)
	{
		DisconnectNamedPipe((*ppOv)->hPipe);
		CloseHandle((*ppOv)->hPipe);
		GlobalFree(*ppOv);
		*ppOv = NULL;
	}
}

void RunAsClient()
{
	BOOL bRet = WaitNamedPipe(TEST_PIPE_NAME, INFINITE);
	if (!bRet)
	{
		printf("WaitNamedPipe Fail, GetLastError:%d\n", GetLastError());
		return;
	}
	HANDLE hFile = CreateFile(TEST_PIPE_NAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf("Open Pipe Fail, GetLastError:%d\n", GetLastError());
		return;
	}
	DWORD dwMode = PIPE_READMODE_MESSAGE;
	bRet = SetNamedPipeHandleState(hFile, &dwMode, NULL, NULL);
	if (!bRet)
	{
		printf("SetNamedPipeHandleState Fail, GetLastError:%d\n", GetLastError());
		return;
	}
	DWORD dwWrite, dwRead;
	TCHAR buf[1024]={0};
Loop:
	printf("Please Input Message: ");
	memset(buf, 0, 1024*sizeof(TCHAR));
	_tscanf(TEXT("%s"), buf);
	if (!WriteFile(hFile, buf, (_tcslen(buf)+1)*sizeof(TCHAR), &dwWrite, NULL))
	{
		printf("WriteFile Fail, GetLastError:%d\n", GetLastError());
		return;
	}
	if (_tcscmp(buf, TEXT("quit")))
	{
		do 
		{
			memset(buf, 0, 1024*sizeof(TCHAR));
			bRet = ReadFile(hFile, buf, 1024*sizeof(TCHAR), &dwRead, NULL);
		} while (!bRet);
		_tprintf(TEXT("Client Recv: %s\n"), buf);
		goto Loop;
	}
	CloseHandle(hFile);
}

void WINAPI CompleteReadRoutine(DWORD dwCode, DWORD dwBytesTrans, LPOVERLAPPED pOv)
{
	OVERLAPPEDX* pX = (OVERLAPPEDX*)pOv;
	_tprintf(TEXT("Server Recv: %s\n"), pX->buf);
	if (_tcscmp(pX->buf, TEXT("quit")) == 0)
	{
		g_bExit = TRUE;
		FreeOverLappedX(&pX);
		return;
	}

	HANDLE hPipe = pX->hPipe;
	if (hPipe == INVALID_HANDLE_VALUE)
	{
		printf("Open Pipe Fail!\n");
		return;
	}
	printf("Please Reply: ");
	memset(pX->buf, 0, 1024*sizeof(TCHAR));
	_tscanf(TEXT("%s"), pX->buf);

	if (!WriteFileEx(hPipe, pX->buf, (_tcslen(pX->buf)+1)*sizeof(TCHAR), pOv, CompleteWriteRoutine))
	{
		printf("WriteFileEx Fail %d\n", GetLastError());
		FreeOverLappedX(&pX);
	}
}

void WINAPI CompleteWriteRoutine(DWORD dwCode, DWORD dwBytesTrans, LPOVERLAPPED pOv)
{
	OVERLAPPEDX* pX = (OVERLAPPEDX*)pOv;
	HANDLE hPipe = pX->hPipe;
	if (hPipe == INVALID_HANDLE_VALUE)
	{
		printf("Open Pipe Fail!\n");
		return;
	}
	memset(pX->buf, 0, 1024*sizeof(TCHAR));
	if (!ReadFileEx(hPipe, pX->buf, 1024*sizeof(TCHAR), pOv, CompleteReadRoutine))
	{
		printf("ReadFileEx Fail %d\n", GetLastError());
		FreeOverLappedX(&pX);
	}
}

void RunAsServer()
{
	HANDLE hPipe;
	BOOL bIOIng, bOk, bFlag;
	DWORD dwErr, dwRet, dwWait;
	//OVERLAPPED
	OVERLAPPED ov;
	ov.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
	OVERLAPPEDX* pX = NULL;
    //CREATENAMEDPIPE
Loop:
	hPipe = CreateNamedPipe(TEST_PIPE_NAME, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, 
		PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 5000, NULL);
	if (hPipe == INVALID_HANDLE_VALUE)
	{
		printf("Server Pipe Create Fail!\n");
		return;
	}
	//CONNECT
	bIOIng = FALSE;
	bOk = ConnectNamedPipe(hPipe, &ov);
	dwErr = GetLastError();
	if (bOk)
	{
		printf("ConnectNamedPipe Fail GetLastError : %d!\n", dwErr);
		return;
	}
	switch (dwErr)
	{
	case ERROR_IO_PENDING:
		bIOIng = TRUE;
		break;
	case ERROR_PIPE_CONNECTED:
		if (SetEvent(ov.hEvent)) 
			break;
	default:
		printf("ConnectNamedPipe Fail GetLastError: %d!\n", dwErr);
		break;
	}
	
	bFlag = TRUE;
	while (!g_bExit)
	{
		dwWait = WaitForSingleObjectEx(ov.hEvent, INFINITE, TRUE);
		switch (dwWait)
		{
		case WAIT_OBJECT_0:
			//Event Signal Or IO pending
			if (bIOIng)
			{
				//Pending
				if (!GetOverlappedResult(hPipe, &ov, &dwRet, FALSE))
				{
					printf("GetOverlappedResult Fail %d!\n", GetLastError());
					return;
				}
			}
			printf("Client Has Connect!\n");
			//IO Over 
			if (bFlag)
			{
				pX = (OVERLAPPEDX*)GlobalAlloc(GPTR, sizeof(OVERLAPPEDX));
				if (!pX)
				{
					printf("GlobalAlloc Fail GetLastError: %d\n", GetLastError());
					return;
				}
				memset(pX, 0, sizeof(OVERLAPPEDX));
				pX->hPipe = hPipe;
				CompleteWriteRoutine(0, 0, (OVERLAPPED*)pX);
				goto Loop;
			}
		case WAIT_IO_COMPLETION:
			//printf("Server WAIT_IO_COMPLETION!\n");
			break;
		default:
			printf("WaitForSingleObjectEx Fail GetLastError: %d\n", dwErr);
			return;
		}
	}
	printf("Server Exit!\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
	char mode;
Loop:
	printf("Command As Following:\n 1 -- Client Mode \n 2 -- Server Mode \n q -- Quit \nPlease select : ");
	scanf("%c", &mode);
	if (mode == 10)
	{
		scanf("%c", &mode);
	}
	switch (mode)
	{
	case '1':
		printf("Run As Client!\n");
		RunAsClient();
		break;
	case '2':
		printf("Run As Server!\n");
		RunAsServer();
		break;
	case 'q':
		break;
	default:
		printf("Invalid mode!\n");
		goto Loop;
	}
	system("@pause");
	return 0;
}