进程的通信 - 命名管道
命名管道概述
命名管道(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_MESSAGE或PIPE_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_READ,GENERIC_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));//底层调用的memsetovlap.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;}
}
执行结果:
进程的通信 - 命名管道相关推荐
- linux命名管道进程间通信,Linux进程间通讯--命名管道
IPC安全 前面总结了匿名管道,如今来看命名管道:因为匿名管道的一个限制就是:只能是有血缘关系的进程间才能够通讯,好比:有两个同祖先的子进程,父子进程等:为了突破这一个限制,想让没有任何关系的两个进程 ...
- C# 管道通信-命名管道(一)
最近在做一个应用程序,涉及到两个应用程序之间的通讯,就想到了用C#的命名管道的方式来实现,经过一番小折腾,总算实现了,现把一些主体的代码粘贴出来与大家分享: 管道通讯会涉及到client端和Serve ...
- 进程通信——命名管道
目录 1.Creat 2.Open 3.Read/Write 4.Wait 5.Close 6.Delete 管道是 SylixOS 进程间通信的一种方式. 管道分为匿名管道 pipe 和命名管道 f ...
- 进程间通讯 ----- 命名管道
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.每个进程都有一个主线程,线程则是cpu调度的基本单位,每个进程都有自己的 ...
- linux 命名管道 c语言 不同进程,进程间通信 - 命名管道实现
命名管道概述 命名管道是通过网络来完成进程之间的通信的,命名管道依赖于底层网络接口, 其中包括有 DNS 服务,TCP/IP 协议等等机制,但是其屏蔽了底层的网络协议细节, 对于匿名管道而言,其只能实 ...
- Linux —进程间的五种通信方式—(半双工管道、命名管道、消息队列、信号、共享内存),外加信号量。直接上代码:
无名管道pipe(半双工):(仅限同一个程序运行) 创建无名管道会生成特殊文件,只存在于内存中 #include <stdio.h> #include <stdlib.h> # ...
- 进程间通信 - 命名管道实现
引子 好,到这里呢,就需要介绍实现进程间通信的第四种方式了, 也就是通过命名管道来实现,前面介绍的那三种方式呢,都是有缺陷或者说局限性太强, 而这里介绍的命名管道相对来说,在这方面就做得好很多了, 比 ...
- 【Linux】进程间通信 - 匿名/命名管道与System V共享内存
目录 前言 一.管道 0.什么是管道 1).管道的概念 2).管道的本质 3).管道指令: "|" 1.匿名管道 1).如何创建匿名管道 2).如何使用匿名管道进行通信 3).匿名 ...
- python 命名管道_命名管道实践
命名管道技术实验 管道介绍 管道(Pipe)是一种进程间的通信机制,Windows.Linux和UNIX都使用这种机制. 管道是通过I/O接口存取的字节流创建管道后,通过使用操作系统的任何读或写I/O ...
最新文章
- 公众号留言-2020-4-1
- Python语言的特点
- 函数计算是如何工作的?
- Spring-学习笔记08【面向切面编程AOP】
- 服务器应用程序不可用您试图在此 Web 服务器上访问的 Web 应用程序当前不可用。请点击 Web 浏览器中的“刷...
- 寒冷的高纬度——我的梦开始的地方
- Magento用的哪个php框架,初识magento框架代码目录
- 零基础转行web前端,如何高效的去学习web前端?
- 10月2场CMDN Club活动专题、视频、资源分享
- 【阅读笔记】Implementation of tactical maneuvers with maneuver libraries
- URL编码的原因及场景
- warning: array subscript is above array bounds
- python格式化字符串固定宽度_python – 格式化固定宽度的字符串(unicode和utf8)
- ECCV2022 Workshop | 复杂环境中的多目标跟踪和分割
- 单例模式与反射的攻防之【 道高一尺,魔高一丈 】
- 求助:tp-link wr720n路由器,想刷打印服务器!
- 高温不怕热,GVS智能家居为你打造夏日清爽雅居
- pytorch BatchNorm参数详解,计算过程
- 【P9】Point to the Expression:Solving Algebraic Word Problems using the Expression-Pointer Transformer
- 卡迪夫大数据专业排名_大数据分析:英超大数据!布莱顿vs卡迪夫
热门文章
- tp5怎么跨控制器调用别的方法
- ulua中lua代码使用反射调用c#详解
- [附源码]计算机毕业设计Python+uniapp基于安卓的校园二手书籍交易APP1yh1y(程序+lw+APP+远程部署)
- 做一个laravel框架下的系统日志
- c语言运行后tecplot云图,tecplot执行fluent后处理截面云图显示.pdf
- uboot源码分析(基于S5PV210)之启动第一阶段
- 医学序列图像定位线绘制基本方法介绍
- monkeyrunner之夜神模拟器的安装与使用(二)
- 我的镜头观,尼康如何搭配镜头(!!强烈推荐!!) 转贴
- DotNetty TLS 开启双向认证加密传输数据