欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-31 23:08:22
...

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

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

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

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

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

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

服务器端命名管道实现的步骤:
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访问方式的模板文件的句柄

相关标签: 命名管道