windows进程间通讯-管道

管道是一种用于在进程间共享数据的机制,其实质是一段共享内存。Windows系统为这段共享的内存设计采用数据流I/0的方式来访问。由一个进程读、另一个进程写,类似于一个管道两端,因此这种进程间的通信方式称作“管道”。 
管道分为匿名管道和命名管道。
1.匿名管道只能在父子进程间进行通信,不能在网络间通信,而且数据传输是单向的,只能一端写,另一端读。
2.命令管道可以在任意进程间通信,通信是双向的,任意一端都可读可写,但是在同一时间只能有一端读、一端写。
下面主要介绍下常用的命名管道:

1.CreateNamePipe

HANDLE WINAPI CreateNamedPipe(
_In_     LPCTSTR               lpName,
_In_     DWORD                 dwOpenMode,
_In_     DWORD                 dwPipeMode,
_In_     DWORD                 nMaxInstances,
_In_     DWORD                 nOutBufferSize,
_In_     DWORD                 nInBufferSize,
_In_     DWORD                 nDefaultTimeOut,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

CreateNamedPipe创建一个命名管道。返回的句柄由管道的服务器端使用
说明
返回值
Long,如执行成功,返回管道的句柄。INVALID_HANDLE_VALUE表示失败。会设置GetLastError
参数表
参数 类型及说明
lpName String,指定管道名,采用的形式是:\\.\管道\管道名。最多可达256个字符的长度,而且不用区分大小写。如果存在指定名字的一个管道,则创建那个管道的一个新实例
dwOpenMode Long,下述常数组的一个组合
下述常数之一(对于管道的所有实例都要一样):
PIPE_ACCESS_DUPLEX 管道是双向的
PIPE_ACCESS_INBOUND 数据从客户端流到服务器端
PIPE_ACCESS_OUTBOUND 数据从服务器端流到客户端
下述常数的任意组合
FILE_FLAG_WRITE_THROUGH 在网络中建立的字节型管道内,强迫数据在每次读写操作的时候通过网络传输。否则传输就可能延迟
FILE_FLAG_OVERLAPPED 允许(但不要求)用这个管道进行异步(重叠式)操作
常数WRITE_DAC, WRITE_OWNER 和 ACCESS_ SYSTEM_SECURITY提供了附加的安全选项
dwPipeMode Long,下述常数组的一个组合:
下述常数之一(管道的所有实例都必须指定相同的常数)
PIPE_TYPE_BYTE 数据作为一个连续的字节数据流写入管道
PIPE_TYPE_MESSAGE 数据用数据块(名为“消息”或“报文”)的形式写入管道
下述常数之一:
PIPE_READMODE_BYTE 数据以单独字节的形式从管道中读出
PIPE_READMODE_MESSAGE 数据以名为“消息”的数据块形式从管道中读出(要求指定PIPE_TYPE_MESSAGE)
下述常数之一:
PIPE_WAIT 同步操作在等待的时候挂起线程
PIPE_NOWAIT(不推荐!) 同步操作立即返回。这样可为异步传输提供一种落后的实现方法,已由Win32的重叠式传输机制取代了
nMaxInstances Long,这个管道能够创建的最大实例数量。必须是1到常数PIPE_UNLIMITED_INSTANCES间的一个值。它对于管道的所有实例来说都应是相同的
nOutBufferSize Long,建议的输出缓冲区长度;零表示用默认设置
nInBufferSize Long,建议的输入缓冲区长度;零表示用默认设置
nDefaultTimeOut Long,管道的默认等待超时。对一个管道的所有实例来说都应相同
lpSecurityAttributes SECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或者传递零值(将参数声明为ByVal As Long,并传递零值),以便使用不允许继承的一个默认描述符

2.ConnetNamePipe

BOOL WINAPI ConnectNamedPipe(
    _In_        HANDLE       hNamedPipe,
    _Inout_opt_ LPOVERLAPPED lpOverlapped
);

ConnectNamedPipe是指示一台服务器等待下去,直至客户机同一个命名管道连接。
返回值
Long,如lpOverlapped为NULL,那么:
如管道已连接,就返回Ture(非零);如发生错误,或者管道已经连接,就返回零(GetLastError此时会返回ERROR_PIPE_CONNECTED)
lpOverlapped有效,就返回零;如管道已经连接,GetLastError会返回ERROR_PIPE_CONNECTED;如重叠操作成功完成,就返回ERROR_IO_PENDING。在这两种情况下,倘若一个客户已关闭了管道,且服务器尚未用DisconnectNamedPipe函数同客户断开连接,那么GetLastError都会返回ERROR_NO_DATA
参数表
参数 类型及说明
hNamedPipe Long,管道的句柄
lpOverlapped OVERLAPPED,如设为NULL(传递ByVal As Long),表示将线程挂起,直到一个客户同管道连接为止。否则就立即返回;此时,如管道尚未连接,客户同管道连接时就会触发lpOverlapped结构中的事件对象。随后,可用一个等待函数来监视连接

下面是一个简单例子:

client:

#include <windows.h>
#include <stdio.h>

#define	PIPE_NAME		"\\\\.\\Pipe\\MyNamedPipe"
#define BUFFER_SIZE		1024

// 命名管道客户端
int main()
{
	HANDLE hPipe;
	/*HANDLE WINAPI CreateFile(
	_In_ LPCTSTR lpFileName,							// 普通文件名或设备文件名
	_In_ DWORD dwDesiredAccess,							// 访问模式(写/读)
	_In_ DWORD dwShareMode,								// 共享模式
	_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,// 指向安全属性的指针
	_In_ DWORD dwCreationDisposition,					// 如何创建
	_In_ DWORD dwFlagsAndAttributes,					// 文件属性
	_In_opt_ HANDLE hTemplateFile						// 用于复制文件句柄
	);*/
	hPipe = CreateFile(PIPE_NAME, 
		GENERIC_READ | GENERIC_WRITE, 
		0, 
		NULL, 
		OPEN_EXISTING,
		0, 
		NULL);

	if (INVALID_HANDLE_VALUE == hPipe){
		printf("Error occurred while connecting to the server: %d",GetLastError());
		return -1;
	}else{
		printf("CreateFile() was successful.\n");
	}

	char szBuffer[BUFFER_SIZE] = {0};
	printf("Enter a message to be sent to the server\n");
	gets_s(szBuffer);
	DWORD cbBytes = 0;

	BOOL bResult = WriteFile(hPipe, szBuffer, strlen(szBuffer) + 1, &cbBytes, NULL);
	if ((!bResult) || (strlen(szBuffer) + 1 != cbBytes)){
		printf("Error occurred while writing to the server: %d\n", GetLastError());
		CloseHandle(hPipe);
		return -1;
	}else{
		printf("WriteFile() was successful..\n");
	}

	bResult = ReadFile(hPipe, szBuffer, sizeof(szBuffer),&cbBytes, NULL);
	if ((!bResult) || (0 == cbBytes)){
		printf("Error occurred while reading from the server: %d\n", GetLastError());
		CloseHandle(hPipe);
		return -1;
	}else{
		printf("ReadFile() was successful...\n");
	}

	printf("Server sent the following message:%s\n",szBuffer);
	CloseHandle(hPipe);
	
	return 0;

}

server:

#include <windows.h>
#include <stdio.h>

#define	PIPE_NAME		"\\\\.\\Pipe\\MyNamedPipe"
#define BUFFER_SIZE		1024

// 命名管道服务端
int main()
{
	BOOL bRet = TRUE;
	HANDLE hPipe;
	
	// 创建命名管道
	hPipe = CreateNamedPipe(
		PIPE_NAME, 
		PIPE_ACCESS_DUPLEX, 
		PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 
		PIPE_UNLIMITED_INSTANCES,
		BUFFER_SIZE, 
		BUFFER_SIZE, 
		NMPWAIT_USE_DEFAULT_WAIT, 
		NULL);

	if (INVALID_HANDLE_VALUE == hPipe){
		printf("Error occurred while creating the pipe: %d\n", GetLastError());
		return -1;
	}else{
		printf("CreateNamedPipe() was successful.\n");
	}

	printf("Waiting for client connection...\n");

	// 等待连接该管道
	BOOL bClientConnected = ConnectNamedPipe(hPipe, NULL);
	if (FALSE == bClientConnected){
		printf("Error occurred while connecting to the client:%d\n", GetLastError());
		CloseHandle(hPipe);
		return 1;
	}else{
		printf("ConnectNamePipe() was successful...\n");
	}

	PULONG ClientProcessID = 0;
	bRet = GetNamedPipeClientProcessId(hPipe, ClientProcessID);
	if (FALSE == bRet){
		printf("Can not Require processid of NamedPipeClient...\n");
	}else{
		printf("Current Client Process ID equal %ld\n", ClientProcessID);
	}

	LPTSTR ClientComputerName = NULL;
	ULONG ClientComputerNameLength = 1024;
	bRet = GetNamedPipeClientComputerName(hPipe, ClientComputerName, ClientComputerNameLength);
	if (FALSE == bRet){
		printf("Can not require Client ComputerName of NamedPipeClient\n");
	}else{
		printf("current Client Computer name of NamedPipe equal %s\n", ClientComputerName);
	}

	char szBuffer[BUFFER_SIZE] = {0};
	DWORD cbBytes = 0;

	BOOL bResult = ReadFile(hPipe, szBuffer, sizeof(szBuffer), &cbBytes, NULL);
	if ((!bResult) || (0 == cbBytes)){
		printf("Error occurred while reading from the client:%d\n",GetLastError());
		CloseHandle(hPipe);
		return 1;
	}else{
		printf("ReadFile() was successfule...\n");
	}
	printf("Client sent the following message: %s\n", szBuffer);
	strcpy_s(szBuffer, "server back msg");

	bResult = WriteFile(hPipe, szBuffer, strlen(szBuffer) + 1, &cbBytes, NULL);
	if ((!bResult) || (strlen(szBuffer) + 1 != cbBytes)){
		printf("\n Error occurred while writing to the client: %d", GetLastError());
		CloseHandle(hPipe);
		return 1;
	}else{
		printf("WriteFile() was successful...\n");
	}
	CloseHandle(hPipe);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1173356881/article/details/81808440