进程的通信 - 命名管道

news2025/1/8 6:05:45

命名管道概述

命名管道(Named Pipes),顾名思义,一个有名字的管道。命名管道的名字主要是用于确保多个进程访问同一个对象。命名管道不仅可以在同一台计算机之间传输数据,甚至能在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信。

命名管道常用的API

创建命名管道实例—CreateNamedPipe

函数原型

HANDLE CreateNamedPipeW(
  [in]           LPCWSTR               lpName,
  [in]           DWORD                 dwOpenMode,
  [in]           DWORD                 dwPipeMode,
  [in]           DWORD                 nMaxInstances,
  [in]           DWORD                 nOutBufferSize,
  [in]           DWORD                 nInBufferSize,
  [in]           DWORD                 nDefaultTimeOut,
  [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
  • 参数lpName

唯一的管道名称。 必须是"\\.\pipe\管道名称“的格式。最多为256个字符长度,且不区分大小。如果已经有相同的命名管道,则会创建那个管道的一个实例

  • 参数dwOpenMode

表示管道的打开方式,同一管道的每个实例必须指定相同的打开方式

模式意义

PIPE_ACCESS_DUPLEX

0x00000003

管道是双向的;服务器和客户端进程都可以读取和写入管道。

PIPE_ACCESS_INBOUND

0x00000001

管道中的数据流仅从客户端传输到服务器。

PIPE_ACCESS_OUTBOUND

0x00000002

管道中的数据流仅从服务器传输到客户端。

同时可以包含以下一个或多个标记,对于同一管道的不同实例,这些模式可以不同

模式意义

FILE_FLAG_FIRST_PIPE_INSTANCE

0x00080000

如果尝试使用此标志创建管道的多个实例,则第一个实例的创建成功,但下一个实例的创建失败,并ERROR_ACCESS_DENIED

FILE_FLAG_WRITE_THROUGH

0x80000000

直写模式已启用。

FILE_FLAG_OVERLAPPED

0x40000000

重叠模式已启用。

还可以包含以下安全访问模式的组合,对于同一管道的不同实例,这些模式可以是不同。

模式意义

WRITE_DAC

0x00040000L

调用方将具有对命名管道的自由访问控制列表 (ACL) 的写入访问权限。

WRITE_OWNER

0x00080000L

调用方将具有对命名管道所有者的写入访问权限。

ACCESS_SYSTEM_SECURITY

0x01000000L

调用方将具有对命名管道的 SACL 的写入访问权限。有关详细信息,请参阅访问控制列表 (ACL) 和SACL 访问权限。
  • 参数dwPipeMode

管道模式,可以指定以下类型模式之一。必须为管道的每个实例指定为相同的类型模式 

模式意义

PIPE_TYPE_BYTE

0x00000000

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

PIPE_TYPE_MESSAGE

0x00000004

数据作为消息流写入管道。

也可以指定以下读取模式之一。同一管道的不同实例可以指定不同的读取模式。

模式意义

PIPE_READMODE_BYTE

0x00000000

数据以字节流的形式从管道读取。此模式可用于PIPE_TYPE_MESSAGEPIPE_TYPE_BYTE

PIPE_READMODE_MESSAGE

0x00000002

数据作为消息流从管道读取。仅当还指定了PIPE_TYPE_MESSAGE时,才能使用此模式。

 还可以指定以下等待模式之一。同一管道的不同实例可以指定不同的等待模式。

PIPE_WAIT

0x00000000

阻止模式已启用。

PIPE_NOWAIT

0x00000001

非阻塞模式已启用。在此模式下,ReadFile,WriteFile和ConnectNamedPipe始终立即返回。

还可以指定以下远程客户端模式之一。同一管道的不同实例可以指定不同的远程客户端模式。

模式意义

PIPE_ACCEPT_REMOTE_CLIENTS

0x00000000

可以接受来自远程客户端的连接,并根据管道的安全描述符进行检查。

PIPE_REJECT_REMOTE_CLIENTS

0x00000008

来自远程客户端的连接将自动被拒绝。
  • 参数nMaxInstances

指定管道可以创建的最大实例数,必须是1到常数255之间的一个值。管道的第一个实例可以指定这个值,管道的其他实例的这个值必须和第一个实例指定的这个值相同。

  • 参数nOutBufferSize

表示管道的输出缓冲区的容量,0表示使用默认大小。

  • 参数nInBufferSize

表示管道的输入缓冲区的容量,0表示使用默认大小

  • 参数nDefaultTimeOut

表示管道的默认等待超时(ms单位),零表示默认超时为50毫秒

  • 参数lpSecurityAttributes

指向SECURITY_ATTRIBUTES结构的指针,该结构体指定命名管道的安全描述符,并确定子进程是否继承返回的句柄。NULL表示使用默认安全描述符,并且无法继承句柄

函数返回值
函数执行成功返回命名管道的句柄,否则返回INVALID_HANDLE_VALUE

等待客户端连接—ConnectNamdePipe

函数原型

BOOL ConnectNamedPipe(
  [in]                HANDLE       hNamedPipe,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);
  • 参数hNamedPipe

表示管道的实例的服务端句柄。也就是CreateNamedPipe函数返回的句柄

  • 参数lpOverlapped

如果CreateNamedPipe第一个参数指定了FILE_FLAG_OVERLAPPED,则此参数不能为NULL,参数就必须是一个手动重置事件对象的句柄。 

例如下面这样

//创建命名管道
hNamedPipe = CreateNamedPipe(.., PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,..);

//手动重置事件对象的句柄
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//创建一个OVERLAPPED结构体
OVERLAPPED ovlap;
ZeroMemory(&ovlap, sizeof(OVERLAPPED));//底层调用的memset
ovlap.hEvent = hEvent;

//等待客户端连接
ConnectNamedPipe(hNamedPipe,&ovlap);

 客户端连接命名管道—WaitNamedpipe

BOOL WaitNamedPipeW(
  [in] LPCWSTR lpNamedPipeName,
  [in] DWORD   nTimeOut
);
  • 参数lpNamedPipeName

表示命名管道的名称

  • 参数nTimeOut

表示等待命名管道的实例可用的毫秒数。可以使用以下值之一,而不是指定毫秒数。

取值意义

NMPWAIT_USE_DEFAULT_WAIT

0x00000000

超时间隔是服务器进程在CreateNamedPipe函数中指定的默认值。

NMPWAIT_WAIT_FOREVER

0xffffffff

在命名管道的实例可用之前,该函数不会返回。

函数返回值

如果管道的实例在超时之前可用,则返回值非零。否则返回零 。

如果指定的命名管道不存在实例,则无论超时值设定如何,WaitNamedPipe函数会立即返回。

如果函数执行成功,则进程可以使用CreateFile函数打开命名管道句柄。返回TRUE表示至少有一个管道实例可用。但也可能打开失败,例如当服务器关闭或者有其他客户端打开了管道。

打开文件或I/O设备—CreateFile

HANDLE CreateFileA(
  [in]           LPCSTR                lpFileName,
  [in]           DWORD                 dwDesiredAccess,
  [in]           DWORD                 dwShareMode,
  [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  [in]           DWORD                 dwCreationDisposition,
  [in]           DWORD                 dwFlagsAndAttributes,
  [in, optional] HANDLE                hTemplateFile
);
  • 参数lpFileName

表示创建或打开的文件或设备名称

  • 参数dwDesiredAccess

请求文件或设备的访问权限,有读、写、读写或无任何操作。GENERIC_READGENERIC_WRITE或两者(GENERIC_READ | GENERIC_WRITE

  • 参数dwShareMode

文件或设备的请求共享模式,有读、写、读写、删除、读写删或者无任何模式

价值意义

0

防止其他进程在请求删除、读取或写入访问权限时打开文件或设备。

FILE_SHARE_DELETE

对文件或设备启用后续打开操作以请求删除访问权限。

FILE_SHARE_READ

启用对文件或设备的后续打开操作以请求读取访问权限。

FILE_SHARE_WRITE

允许对文件或设备执行后续打开操作以请求写入访问权限。
  • 参数 lpSecurityAttributes

指向SECUTITY_ATTRIBUTES结构的指针,参数为NULL表示任何子进程都不能继承CreateFile返回的句柄

  • 参数dwCreationDisposition

表示对存在会不存在的文件或设备执行的操作,对存在的文件或设备通常设置为OPEN_EXISTING

取值意义

CREATE_ALWAYS

始终创建新文件。

CREATE_NEW

仅当文件尚不存在时才创建新文件。

OPEN_ALWAYS

始终打开文件。

OPEN_EXISTING

仅打开文件或设备(如果存在)。

TRUNCATE_EXISTING

打开文件并将其截断,使其大小为零字节(仅当它存在时)。
  • 参数dwFlagsAndAttributes

表示文件或设备属性和标志,FILE_ATTRIBUTE_NORMAL是文件的通用默认属性 

  • 参数hTemplateFile

此参数可为NULL,打开现有文件时,创建文件时可用忽略这个参数

函数返回值

函数执行成功,返回值是指定文件、设备、命名管道或邮槽

函数失败返回INVALID_HANDLE_VALUE

Demo示例:

 

两个MFC应用,给第一个应用添加三个菜单分别为”创建管道“,”读取数据“,”写入数据“作为服务端。点击”创建管道“服务端会创建一个管道,然后等待连接;点击“读取数据”服务端会读取管道中的数据,然后通过消息提示框显示出来; 点击“写入数据”服务端会向命名管道写入数据。

第二个应用做客户端,为其添加三个菜单分别为“连接管道”、“读取数据”、“写入数据”。点击“连接管道”客户端会去连接命名管道;点击“读取数据”客户端会读取管道中的数据,然后通过消息提示框显示出来;点击“写入数据”客户端会向管道中写入数据。

服务端

创建管道:

服务端调ConnectNamedPipe等待客户端连接,这里我将参数lpOverlapped设定为一个手动重置的事件对象,当成功连接后,系统会将这个事件对象设为已通知状态,我们可以监听这个对象来判断客户端是否成功连接。

hNamedPipe是一个HANDLE类型的类属性,在类的构造函数里初始化,析构函数里销毁。

  

  

void CChildView::OnCreatNamePipe()
{
	//1.创建一个命名管道
	LPCTSTR szPipeName = TEXT("\\\\.\\pipe\\mypipe");
	hNamedPipe = CreateNamedPipe(szPipeName,
		PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
		PIPE_TYPE_BYTE,
		1, 1024, 1024, 0, NULL
	);
	if (hNamedPipe == INVALID_HANDLE_VALUE) {
		TRACE("Create NamedPipe failed witch %d\n", GetLastError());
		MessageBox(_T("创建命名管道失败"));
		return;
	}

	//连接完成后,系统会将OVERLAPPED的hEvent设置为已通知状态事件
	//这里创建一个事件赋值给hEvent,用来监控其改变
	HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (hEvent == NULL) {
		MessageBox(_T("创建事件失败"));
		CloseHandle(hNamedPipe);
		hNamedPipe = NULL;
		return;
	}
	//2.等待客户端的连接
	OVERLAPPED ovlap;
	ZeroMemory(&ovlap, sizeof(OVERLAPPED));//底层调用的memset
	ovlap.hEvent = hEvent;

	if (!ConnectNamedPipe(hNamedPipe,&ovlap)) {
		//标准判断操作
		if (ERROR_IO_PENDING != GetLastError()) {
			MessageBox(_T("等待客户端连接失败"));
			CloseHandle(hNamedPipe);
			hNamedPipe = NULL;
			return;

		}
	}
	if (WaitForSingleObject(hEvent, INFINITE) == WAIT_FAILED) {
		//
		MessageBox(_T("等待对象失败"));
		CloseHandle(hNamedPipe);
		CloseHandle(hEvent);
		hNamedPipe = NULL;
		hEvent = NULL;
		return;
	}
	//否则就连接成功
}

读数据:

void CChildView::OnSreadNamePipe()
{
	char szBuf[100] = { 0 };
	DWORD dwRead;
	if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL)) {
		MessageBox(_T("读取数据失败"));
		return;
	}
	MessageBox((CString)szBuf);
}

写数据:

void CChildView::OnSwriteNamePipe()
{
	char szBuf[] = "霸道小明超秀";
	DWORD dwWrite;
	if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) {
		MessageBox(_T("写入数据失败"));
		return;
	}
}

客户端 

 连接管道:

hNamedPipe是一个HANDLE类型是类属性,在构造函数里初始化,在析构函数里销毁。

   

  

void CChildView::OnConnectNamePipe()
{ 
	//连接命名管道
	LPCTSTR szNamedPipe = TEXT("\\\\.\\pipe\\mypipe");
	if (0 == WaitNamedPipe(szNamedPipe, NMPWAIT_WAIT_FOREVER)) {
		MessageBox(_T("当前没有可以利用的管道"));
		return;
	}
	hNamedPipe = CreateFile(szNamedPipe,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (hNamedPipe == INVALID_HANDLE_VALUE) {
		TRACE("Create File failed with %d\n", GetLastError());
		MessageBox(_T("打开命名管道失败!"));
		hNamedPipe = NULL;
		return;
	}
	//连接成功
}

读数据:

void CChildView::OnReadNamePipe()
{
	char szBuf[100] = { 0 };
	DWORD dwRead;
	if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL)) {
		MessageBox(_T("读取数据失败"));
		return;
	}
	MessageBox((CStringW)szBuf);
}

写数据:

void CChildView::OnWriteNamePipe()
{
	char szBuf[] = "霸道小明超秀";
	DWORD dwWrite;
	if(!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) {
		MessageBox(_T("写入数据失败"));
		return;
	}
}

执行结果:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zbrush 导出置换 然后导入vray 在 3ds max 和 maya 设置

注:方法很多,这个只是个人学习总结,如果不合适,可另外学习其他方法! 第一步: Zbrush 导出置换和法线设置: 第二步: 3Ds max 设置方式建议用exr格式(由于导出的时候…

科目一过关技巧

口诀 3让6违——题目中看到“6分”选“违”字;看到“违”字选6分(“违”法停车的违字除外,选9分);看到“让”就3分红高蓝低——红色圈圈最高,蓝色最低虚可实禁——车辆可以压虚线,不能压实线&a…

Windows11 配置Cuda cuDNN Pytorch环境

文章目录1 安装CudaNote 安装失败的情况2 安装cuDNN3 安装Anaconda4 安装Pytorch5 使用Pycharm进行验证6 结束1 安装Cuda 进入 developer cuda: https://developer.nvidia.com/ 之后自定义路径进行安装即可 必装CUDA,其他情况自己选择 自定义路径 Document与Deve…

Python表白比心

本文介绍运用Python中的turtle库控制函数画比心图。    文章目录一、效果展示二、代码详解1 导入库2 播放音乐3 画手4 定义画心的函数5 定义写名字的函数并实现动态画心一、效果展示 在介绍代码之前,先来看下本文的实现效果。 可以参考Pinstaller(Python打包为exe…

[附源码]java毕业设计网上手机商城的设计与实现

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

JS,DOM试题2,在实践中应用,非常详细!!

列表收缩 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><style>ul,li{list-style: none;padding: 0;margin: 0;}ul{display: none;}h3{margin: 0;background: cornflowerblue;}div{text-indent: 20…

基于FFmpeg的Java视频Mp4转GIF初探

背景 在一些业务场景中&#xff0c;会有如下的一些要求&#xff1a;比如有用户需要将Mp4视频转为Gif动图。当然有一些小伙伴说可以使用系统截图&#xff0c;然后使用之前提到过的技术&#xff1a;GIF图像动态生成-JAVA后台生成。需要处理的素材比较少&#xff0c;就一两个视频&…

最全Python操作excel代码,让你每天早下班两小时

在数字化时代&#xff0c;很多人工作中经常和excel打交道。本文介绍Python操作excel的脚本&#xff0c;让你工作效率更高。    文章目录一、安装openpyxl模块二、加载库三、创建文件和工作表四、在工作表指定单元格写数据五、设置单元格的颜色字体六、在excel中写入表格一、安…

【数据结构初阶】C语言从0到1带你了解直接插入排序

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【数据结构初阶】 ✒️✒️本篇内容&#xff1a;深入剖析直接插入排序 &#x1f6a2;&#x1f6a2;作者简介&#xff1a;计算机海洋的新进船长一枚&#xf…

等保整改之开启Nacos认证-漏扫发现我们使用Nacos时存在未授权访问的漏洞

背景 还是之前的一个小项目&#xff0c;部署在专网中&#xff0c;等保在做了一次漏扫后&#xff0c;说是有个高危漏洞要求整改。打开漏洞扫描报告后&#xff0c;总体网络风险级别为&#xff1a;比较危险&#xff1a; nacos未授权访问漏洞 &#xff0c;漏洞详细信息如下&#x…

Linux基本用户操作

1.查看用户名 指令&#xff1a;whoami 在Linux下查看本用户下的用户名&#xff0c;可以在普通用户和root超级用户下操作&#xff0c;如下&#xff1a; 其实&#xff0c;查看用户名也可以不用指令就能查看&#xff1a; 箭头所指的就是用户名&#xff0c;root用户名就是root。 2.…

第2章 持久化初始数据到指定表

004 AuthorityScopeEnum、Role、Topic、TaskInfoDto、TasksQz AuthorityScopeEnum&#xff1a;该枚举定义了6种当前程序的访问权限&#xff0c;前程序通过该枚举实例选定其中(NONE(-1&#xff1a;无任何权限)/Custom(1&#xff1a;自定义权限)/MyDepart(2&#xff1a;本部门权…

Typescript:(一)基本使用

TypeScript 定义&#xff1a;Typescript是拥有类型的JavaScript超集 它可以编译成普通&#xff0c;干净&#xff0c;完整的JavaScript代码 我们可以将TypeScript理解成加强版的JavaScript。 JavaScript所拥有的特性&#xff0c;TypeScript全部都是支持的&#xff0c;并且它紧…

Linux系统挂载命令mount(U盘、移动硬盘、光盘)

Linux系统不像windows系统可以自动识别加载新设备&#xff0c;Linux系统需要手动识别&#xff0c;手动加载。Linux中一切皆文件。文件通过一个很大的文件树来组织&#xff0c;文件树的根目录是&#xff1a;/&#xff0c;从根目开始录逐级展开。这些文件通过若干设备铺展开。 命…

BCG 对话框表格控件CBCGPGridCtrl显示子

1、1、MFC窗口中拖放Picture Control 2、 void CSimpleGridSampleDlg::_FillGrid() { CWaitCursor wait; // Create grid tree: CRect rectClient; GetClientRect(rectClient); m_wndGrid.Create(WS_CHILD | WS_VISIBLE, rectClient, this, ID_GRID); m_wndGri…

SAR回波的多普勒特性

专栏目录链接: SAR成像专栏目录 今天我们来看看SAR回波的多普勒特性。 首先推导下正侧视下SAR回波的多普勒频率公式,前提条件: 正侧视不考虑平台运动的不稳定性忽略地球曲率忽略地球自转的影响 根据多普勒效应原理可得SAR回波的多普勒频率(可以回顾下:《雷达导论PART IV.…

C++之二叉搜索树详解

文章目录前言一、二叉搜索树的概念二、二叉搜索树的操作1.节点类2.二叉搜索树类内部定义3.遍历操作4.构造函数5.拷贝构造函数6.赋值运算符重载7.析构函数8.插入函数非递归实现递归实现9.删除函数非递归实现递归实现10.查找函数非递归实现递归实现三、二叉搜索树的应用K模型KV模…

索引和事务

文章目录 1.索引的含义以及应用 2.索引的查看、创建 3.带主键的索引底层结构 4.事务的含义 5.事务的特性 6.JDBC 一.索引的含义及应用 1.索引我们可以认为是文章的目录&#xff0c;有了它&#xff0c;我们可以更加快速的 查看到我们想要查找的内容。 2.并不是说我们加了索引&…

一周侃 | 周末随笔及推荐

前言 每周一次的闲聊胡侃又来啦&#xff01;这一周世界发生了许多大事&#xff0c;从举世瞩目的中美元首会晤到新的防疫政策二十条出来之后各地防疫政策的转变&#xff0c;再到俄乌冲突持续进行&#xff0c;联大通过俄罗斯赔偿计划……百年未有之大变局正加速演进&#xff0c;…

【k8s】8、service详解

文章目录一、Service详解1、Service介绍1.1 userspace模式1.2 iptables 模式1.3 ipvs模式2、Service类型3、Service使用3.1 实现环境准备3.2 Cluster类型的Service3.2.1 cluster类型的生成ip3.2.2 cluster类型不生成ip3.3 NodePort类型的service3.4 LoadBalancer类型的Service3…