【网络编程学习笔记03】进程间通讯-命名管道

进程间通讯-命名管道

前置知识:学习了邮槽的知识,了解CreateFile、ReadFile、WriteFile函数的使用方法。

命名管道是一种不但能在同一机器上实现两个进程通讯,还能在网络中不同机器上的两个进程之间通讯的机制。与邮槽不同,命名管道传输数据是采取基于连接并且可靠的传输方式,所以命名管道传输数据只能一堆一进行传输。

1.创建命名管道

创建命名管道可以用CreateNamedPipe()函数,函数原型如下:

HANDLE CreateNamedPipe(
  LPCTSTR lpName,                             // pipe name
  DWORD dwOpenMode,                           // pipe open mode
  DWORD dwPipeMode,                           // pipe-specific modes
  DWORD nMaxInstances,                        // maximum number of instances
  DWORD nOutBufferSize,                       // output buffer size
  DWORD nInBufferSize,                        // input buffer size
  DWORD nDefaultTimeOut,                      // time-out interval
  LPSECURITY_ATTRIBUTES lpSecurityAttributes  // SD
);

如果调用成功,则返回创建命名管道的句柄。否则,函数返回INVALID_HANDLE_VALUE。

  • 参数lpName表示创建的命名管道名称。格式为“\\.\pipe\pipename”。在VC环境下应修改为“\\\\.\\pipe\\pipename”,如果用户希望在不同的计算机的两个进程之间通讯,可以将“.”换成远程计算机的名称。
  • 参数dwOpenMode表示命名管道的打开方式,该参数取值如下表:

模 式 取 值

模 式 说 明

PIPE_ACCESS_DUPLEX

指定双向模式,服务端与客户端都可以从命名管道中读取或写入数据

PIPE_ACCESS_INBOUND

命名管道的数据只能从客户端到服务端,即服务端只能读取数据,客户端只能写入数据

PIPE_ACCESS_OUTBOUND

命名管道的数据只能从服务端到客户端,即服务端只能写入数据,客户端只能读取数据

FILE_FLAG_WRITE_THROUGH

允许写直通模式。当用户指定该值时,写入数据的一方要等到写入的数据到达另一方的数据缓冲区之后,才会成功返回

FILE_FLAG_OVERLAPPED

允许使用重叠模式。采用该模式可以使一些耗费时间的操作在后台执行,在重叠模式下,一个线程可以在多个管道实例上同时处理输入与输出

WRITE_DAC

调用线程对命名管道的任意访问控制列表都可以进行写入操作

WRITE_OWNER

调用者对命名管道的所有者可以进行写入操作

ACCESS_SYSTEM_SECURITY

调用者对命名管道的安全访问控制列表可以进行写入操作

  • 参数dwPipeMode表示句柄管道的类型、读取以及等待方式,该参数取值如下表:

取 值

说 明

PIPE_TYPE_BYTE

数据以字节流的形式写入管道

PIPE_TYPE_MESSAGE

数据以消息流的形式写入管道

PIPE_READMODE_BYTE

以字节流的形式从管道中读取数据

PIPE_READMODE_MESSAGE

以消息流的形式从管道中读取数据

PIPE_WAIT

允许阻塞模式

PIPE_NOWAIT

允许非阻塞模式

  • 参数nMaxInstances表示管道能够创建实例的最大数目。其取值范围在1~PIPE_UNLIMITED_INSTANCES。如果将该值设为PIPE_UNLIMITED_INSTANCES,则创建的管道实例数据仅限于操作系统。
  • 参数nOutBufferSize表示输出缓冲区的大小。
  • 参数nInBufferSize表示输入缓冲区的大小。
  • 参数nDefaultTimeOut表示超时值,使用同一管道的不同实例必须将该参数取同样的超时值。
  • 参数lpSecurityAttributes是指向结构体SECURITY_ATTRIBUTES的指针,表示命名管道的安全属性。

例子:创建一个命名管道

HANDLE hpip;
hpip=CreateNamedPipe("\\\\.\\pipe\\pipename",PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE,
PIPE_UNLIMITED_INSTANCE,1024,1024,0,NULL);

2.连接命名管道

对于服务端而言

可以调用ConnectNamedPipe()函数等待客户端的连接请求。该函数原型如下:

BOOL ConnectNamedPipe(
  HANDLE hNamedPipe,          // handle to named pipe
  LPOVERLAPPED lpOverlapped   // overlapped structure
);

该函数只能对命名管道的服务器方进行调用,其作用是等待客户端的连接请求。

  • 参数hNamedPipe表示命名管道的句柄。
  • 参数lpOverlapped是指向结构体OVERLAPPED的指针,如果创建的管道是使用FILE_FLAG_OVERLAPPED标记打开,那么该参数指向的结构体中必须包含一个人工重置的事件对象。

例子:用户在服务器端使用该函数等待客户端的连接请求

OVERLAPPED ovi={0};
If (::ConnectNamedPipe(hpip,&ovi)){
	MessageBox("客户端连接成功");
}

对于客户端而言

需要在连接服务端创建的命名管道之前判断该命名管道是否可用,所以需要使用WaitNamedPipe()函数。该函数原型如下:

BOOL WaitNamedPipe(
  LPCTSTR lpNamedPipeName,  // pipe name
  DWORD nTimeOut            // time-out interval
);

该函数的作用是判断服务端创建的命名管道是否可用。

  • 参数lpNamedPipeName表示命名管道的名称。
  • 参数nTimeOut表示超时的时间间隔。其取值如下表所示:

取 值

说 明

NMPWAIT_USE_DEFAULT_WAIT

表示超时时间是服务端创建命名管道时所指定的超时时间

NMPWAIT_WAIT_FOREVER

表示该函数将一直等待,直到出现可用的命名管道

当函数调用成功反对TRUE,调用失败返回FALSE。

接着,客户端使用函数CreateFile()将该命名管道打开以获得该管道的句柄。

3.读写命名管道

不论服务端还是客户端,只要双方命名的管道连接成功,用户便可以调用函数ReadFile()和WriteFile()对命名管道进行读写操作。

4.命名管道服务端实例

#include <windows.h>
#include <stdio.h>
int main()
{
	HANDLE hpip;
	OVERLAPPED ovi={0};
	char buf[200];
	DWORD readbuf;
	hpip=CreateNamedPipe("\\\\.\\pipe\\pipename", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);
	printf("创建管道成功,正在等待客户端连接!\r\n");
	if (::ConnectNamedPipe(hpip, &ovi)){
		printf("客户端连接成功!\r\n");
		printf("正在读取数据!\r\n");
	}
	if (::ReadFile(hpip, buf, 200, &readbuf, NULL)){
		printf("数据读取成功!\r\n");
		printf("读取的数据是:%s\r\n",buf);

	}
	else{
		printf("读取数据失败\r\n");
	}
	return 0;
}

5.命名管道客户端实例

#include <windows.h>
#include <stdio.h>
int main()
{
	HANDLE hpip;
	OVERLAPPED ovi={0};
	char buf[]="blog.csdn.net/encal";
	DWORD readbuf;
	printf("正在连接命名管道!\r\n");
	if (::WaitNamedPipe("\\\\.\\pipe\\pipename", NMPWAIT_WAIT_FOREVER)){
		hpip=CreateFile("\\\\.\\pipe\\pipename", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hpip == INVALID_HANDLE_VALUE){
			printf("打开命名管道失败\r\n");
		}
		else{
			if (WriteFile(hpip, buf, sizeof(buf), &readbuf, NULL)){
				printf("数据写入成功\r\n");
			}
			else{
				printf("数据写入失败\r\n");
			}
		}
	}
	else{
		printf("连接命名管道失败\r\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值