C++命名管道详解及简单案例(基于VS2013)

在介绍命名管道之前首先要区分匿名管与命名管道的区别:

1、匿名管道只能在本地的机器上的父子进程间通信

2、命名管道不仅可以在本机上实现两个进程间的通信,还可以跨网络实现两个进程间的通信

好了先上一下程序的运行情况:程序下载地址


其实程序来说相对比较简单,这里先放上服务器端和客户端使用命名管道的步骤:

服务器端命名管道实现的步骤:
1、创建命名管道CreateNamedPipe
2、等待客户端连接ConnectNamedPipe
3、接收客户端发送数据ReadFile & 向客户端发送数据WriteFile
4、关闭管道CloseHandle


客户端命名管道实现的步骤:
1、判断是否有可以用的命名管道WaitNamedPipe
2、打开管道CreateFile
3、接收客户端发送数据ReadFile & 向客户端发送数据WriteFile
4、关闭管道CloseHandle

但是程序中有几个函数的使用方法及参数需要详细的进行介绍:

首先是服务器端的主函数代码:

int main()
{
	char buf[256] = "";
	DWORD rLen = 0;
	DWORD wLen = 0;
	HANDLE hPipe = NULL;
	hPipe = CreateNamedPipe(
		TEXT("\\\\.\\Pipe\\pipeTest"),							//管道名  
		PIPE_ACCESS_DUPLEX,										//管道类型,双向通信  
		PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,  //管道参数  
		PIPE_UNLIMITED_INSTANCES,								//管道能创建的最大实例数量  
		0,														//输出缓冲区长度 0表示默认  
		0,														//输入缓冲区长度 0表示默认  
		NMPWAIT_WAIT_FOREVER,									//超时时间,NMPWAIT_WAIT_FOREVER为不限时等待
		NULL);													//指定一个SECURITY_ATTRIBUTES结构,或者传递零值.
	if (INVALID_HANDLE_VALUE == hPipe)
		cout << "创建管道失败: " << GetLastError() << endl;
	else
	{
		cout << "这是命名管道测试程序中的服务器端" << endl;
		cout << "现在等待客户端连接..." << endl;
		if (!ConnectNamedPipe(hPipe, NULL))						//阻塞等待客户端连接。  
		{
			cout << "连接失败!" << endl;
			return 1;
		}
		else
			cout << "连接成功!" << endl;
		if (!ReadFile(hPipe, buf, 256, &rLen, NULL))			//接受客户端发送数据
		{
			cout << "从客户端接收并读取数据!" << endl;
			return 2;
		}
		else
			cout << "客户端接收的数据为 : " << buf << endl << "数据长度为 " << rLen << endl;
		char strMessage[] = "命名管道测试程序";
		WriteFile(hPipe, strMessage, sizeof(strMessage), &wLen, 0); //向客户端发送数据
		CloseHandle(hPipe);											//关闭管道句柄 
	}
	system("pause");
	return 0;
}

结合前面的步骤,我们介绍几个函数的参数:

CreateNamedPipe:

//创建命名管道的函数的使用
CreateNamedPipe("\\\\.\\Pipe\\Test",PIPE_ACCESS_DUPLEX,PIPE_NOWAIT,10,1024,1024,100,NULL)
1、为创建的管道命名
2、指定管道的访问方式、重叠方式、写直通方式以及管道句柄的安全访问方式(PIPE_ACCESS_DUPLEX这里指双向模式)
3、指定管道句柄的类型、读取和等待方式(PIPE_NOWAIT指允许非阻塞方式)
4、指定管道能够创建的实例的最大数目
5、指定为输出缓冲区所保留的字节数
6、指定为输入缓冲区所保留的字节数
7、指定默认超时时间,单位ms,同一管道的不同实例指定值需要相同
8、指向SECURITY_ATTRIBUTES结构的指针,该结构指定了命名管道的安全描述符

ConnectNamedPipe:

//服务器等待客户端的连接请求的到来(并非连接服务器端的命名管道!)
ConnectNamedPipe(hPipe, NULL)	
1、指向一个命名管道实例的服务器的句柄,该句柄由CreateNamedPipe函数返回
2、指向OVERLAPPED结构体的指针,默认为NULL,表明使用默认的同步IO方式

接收客户端发送数据ReadFile & 向客户端发送数据WriteFile:

//文件的写入
WriteFile(hPipe, strMessage, sizeof(strMessage), &wLen, 0)
1、指定要写入数据的文件的句柄
2、指向包含将要将要写入文件的数据的缓冲区的指针
3、指明要向文件中写入的字节数
4、用来接收实际写入到文件中的字节数
5、指向OVERLAPPED结构体的指针,默认为NULL,表明使用默认的同步IO方式

//文件的读取
ReadFile(hPipe, buf, 256, &rLen, NULL)
1、指定要读取数据的文件的句柄
2、指向包含将要将要接收的文件中读取数据的缓冲区的指针
3、指明要向文件中读取的字节数
4、用来接收实际读取到的字节数
5、指向OVERLAPPED结构体的指针,默认为NULL,表明使用默认的同步IO方式

CloseHandle:

CloseHandle(hPipe);											//关闭管道句柄 

然后就是客户端的主函数程序:

int main()
{
	cout << "这是命名管道测试程序的客户端" << endl;
	char buf[256] = "";
	DWORD rLen = 0;
	DWORD wLen = 0;
	Sleep(1000);						//等待管道创建成功!  
	if (!WaitNamedPipe(TEXT("\\\\.\\Pipe\\pipeTest"), NMPWAIT_WAIT_FOREVER))
	{
		cout << "connect the namedPipe failed!" << endl;
		return 1;
	}

	HANDLE hPipe = CreateFile(          //创建管道文件,即链接管道  
		TEXT("\\\\.\\Pipe\\pipeTest"),	//管道名称  
		GENERIC_READ | GENERIC_WRITE,   //文件模式  
		0,                              //是否共享  
		NULL,                           //指向一个SECURITY_ATTRIBUTES结构的指针  
		OPEN_EXISTING,                  //创建参数  
		FILE_ATTRIBUTE_NORMAL,          //文件属性,NORMAL为默认属性  
		NULL);                          //模板创建文件的句柄  

	if (INVALID_HANDLE_VALUE == hPipe)
	{
		cout << "打开通道失败!" << endl;
		return 2;
	}
	char strMessage[] = "命名管道测试程序";
	if (!WriteFile(hPipe, strMessage, sizeof(strMessage), &wLen, 0)) //向管道发送数据  
	{
		cout << "向通道写数据失败!" << endl;
		return 3;
	}
	if (!ReadFile(hPipe, buf, 256, &rLen, NULL))					//读取管道数据
	{
		cout << "从通道读数据失败!" << endl;
		return 4;
	}
	else
		cout << "从服务器端接收数据 : " << buf << endl << "数据长度为:" << rLen << endl;

	Sleep(1000);   //执行挂起一段时间
	CloseHandle(hPipe);					//关闭管道  
	system("pause");
	return 0;
}

客户端的程序与服务器端相同的函数就不再介绍了,这里只说一下客户端单独用到的两个函数

WaitNamedPipe:

WaitNamedPipe(TEXT("\\\\.\\Pipe\\pipeTest"), NMPWAIT_WAIT_FOREVER)
1、指定命名管道的名称
2、指定超时间隔,NMPWAIT_WAIT_FOREVER表示一直等待,直到出现了一个可用的命名管道的实例

CreateFile:

CreateFile("\\\\.\\Pipe\\Test",GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
1、指定用于创建或打开的对象的名称
2、指定对象的访问方式,GENERIC_WRITE表示指定对象具有写访问
3、指定共享方式,如果此参数为0,表示对象不能被共享
4、指向SECURITY_ATTRIBUTES结构的指针,该结构指定了命名管道的安全描述符,如果没有特殊的需求,默认值为NULL
5、指定如何创建文件(OPEN_EXISTING表示打开文件,如果文件不存在,则函数调用失败)
6、设置文件属性和标志(FILE_ATTRIBUTE_NORMAL表示该文件没有其他属性设置)
7、指定具有GENERIC_READ访问方式的模板文件的句柄

猜你喜欢

转载自blog.csdn.net/qq_15029743/article/details/79508568