管道的分类

管道其实际就是一段共享内存,只不过Windows规定需要使用I/O的形式类访问这块共享内存,管道可以分为匿名管道和命名管道。

  • 匿名管道就是没有名字的管道,其支持单向传输数据,如果需要双向传送数据就需要创建两条管道。而且其只支持具有父子关系的两个进程进行通信,不能在网络间进行通信。
  • 命名管道就是有名字的管道,其支持双向传输数据,因此一般还需要创建一条命名管道实现两个进程间的通讯。他的实现类似于我们了解的客户端/服务端。他能在任意进程间进行通讯。

匿名管道

typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; //结构大小
LPVOID lpSecurityDescriptor; //安全属性(一般为NULL采用默认属性)
BOOL bInheritHandle; //管道句柄是否可继承
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

匿名管道在创建前需要设置其安全描述符结构,此结构的bInheritHandle字段规定管道句柄是否可继承,也就是其此进程的子进程是否可以继承此管道句柄,如果不能继承那么子进程就无法使用此管道句柄进行管道数据的读写。

BOOL CreatePipe(
PHANDLE hReadPipe, //保存管道用来读数据的管道句柄的指针
PHANDLE hWritePipe, //保存管道用来写数据的管道句柄的指针
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize
);

利用CreatePipe()创建匿名管道,nSize指定为管道缓冲区的大小,如果值为0就采用默认大小。

//伪代码
SECURITY_ATTRIBUTES.dwFlags = STARTF_USESTDHANDLES;
bInheritHandles = TRUE;

接着就是创建子进程,然后通过管道与此子进程进行通信。创建此子进程的STARTUPINFO结构的dwFlags字段要为STARTF_USESTDHANDLES这样改变子进程的标准输入输出才有效,否则无效。CreateProcess创建子进程时其第五个参数bInheritHandles要为TRUE,表示此进程创建的子进程可以继承本进程的句柄,这样本进程创建的管道句柄才能被子进程使用用来与本进程通信。

BOOL WriteFile(
HANDLE hFile, //对应写数据的管道句柄
LPCVOID lpBuffer, //保存写入数据的缓冲区
DWORD nNumberOfBytesToWrite, //写入数据的大小
LPDWORD lpNumberOfBytesWritten, //返回实际写入数据的大小
LPOVERLAPPED lpOverlapped //异步操作一般为NULL
); BOOL ReadFile(
HANDLE hFile, //对应读数据的管道句柄
LPVOID lpBuffer, //保存读取数据的缓冲区
DWORD nNumberOfBytesToRead, //读取数据缓冲区的大小
LPDWORD lpNumberOfBytesRead, //返回实际读取的数据大小
LPOVERLAPPED lpOverlapped ////异步操作一般为NULL
);

之后就通过WriteFile()和ReadFile()利用对应的管道句柄来通过管道与子进程进行通信。

HANDLE hMyWrite, hMyRead, hCmdWrite, hCmdRead;	

void _Init()
{
SECURITY_ATTRIBUTES as; //安全描述符结构
as.nLength = sizeof(SECURITY_ATTRIBUTES);
as.bInheritHandle = TRUE; //管道句柄可继承
as.lpSecurityDescriptor = NULL; //NULL表示使用默认的安全属性 CreatePipe(&hCmdRead, &hMyWrite, &as, 0); // my ----> cmd 管道
CreatePipe(&hMyRead, &hCmdWrite, &as, 0); // my <---- cmd 管道 STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi)); si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES; //意思是可以更改cmd的标准输入输出
si.hStdInput = hCmdRead; //子进程的标准输入为my ----> cmd管道的读管口
si.hStdOutput = hCmdWrite; //子进程的标准输入为my <---- cmd管道的写管口
si.hStdError = hCmdWrite; CreateProcess(TEXT("C:\\Windows\\System32\\cmd.exe"),
NULL,
NULL,
NULL,
TRUE, //句柄可继承
CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi);
} int main(int argc, char* argv[])
{
_Init(); //初始化管道 char szWriteBuffer[MAX_PATH];
printf("%s", "请输入需要执行的cmd命令:");
scanf("%s", szWriteBuffer); WriteFile(hMyWrite, szWriteBuffer, sizeof(szWriteBuffer), NULL, NULL); //向管道中写数据
Sleep(1); DWORD dwSize; //每次从管道中读取数据的大小
char szBuffer1[MAX_PATH];
char szBuffer2[0x1000]; //存放最终的数据
while(1) //循环读取
{
memset(szBuffer1, 0, sizeof(szBuffer1));
ReadFile(hMyRead, szBuffer1, MAX_PATH, &dwSize, NULL); //从管道中读取数据
lstrcat(szBuffer2, szBuffer1);
if (dwSize != MAX_PATH)
break;
} printf("cmd的返回为:\n%s:", szBuffer2);
return 0;
}

上面的例子通过建立本进程与cmd进程之间的两条匿名管道进行数据的传递。

命名管道

利用命名管道进行两个进程间的通讯就类似于将两个进程一个当成服务端,一个当成客户端。

HANDLE CreateNamedPipeA(
LPCSTR lpName, //管道名称
DWORD dwOpenMode, //打开模式(单向还是双向)
DWORD dwPipeMode, //管道模式
DWORD nMaxInstances, //此管道最大的实例数
DWORD nOutBufferSize, //一般为0
DWORD nInBufferSize, //一般为0
DWORD nDefaultTimeOut, //表示管道的默认等待超时,NMPWAIT_WAIT_FOREVER表示一直等待
LPSECURITY_ATTRIBUTES lpSecurityAttributes //使用默认安全属性NULL
);

服务端创建命名管道返回管道句柄,管道的名称需要遵循入下格式\.\pipe\name,名字最长为256个字符。

BOOL ConnectNamedPipe(
HANDLE hNamedPipe, //命名管道句柄
LPOVERLAPPED lpOverlapped //一般为NULL
);

服务端创建完命名管道后就是等待客户端连接。

BOOL WaitNamedPipeA(
LPCSTR lpNamedPipeName, //命名管道名称
DWORD nTimeOut //等待时长,NMPWAIT_WAIT_FOREVER表示一直等待
);

客户端通过命名管道的名称连接服务端。

连接成功后通过CreateFile()打开命名管道并获得管道句柄,接着利用管道句柄通过ReadFile()和WriteFile()进行通讯。

Windows进程间通讯(IPC)----管道的更多相关文章

  1. High Performance Networking in Google Chrome 进程间通讯(IPC) 多进程资源加载

    小结: 1. 小文件存储于一个文件中: 在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里.其中有索引文件(在浏览器启动时加载到内存中),数据文件( ...

  2. Android AIDL 进行进程间通讯(IPC)

    编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...

  3. QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开     本文地址:h ...

  4. Windows进程间通讯(IPC)----消息队列

    消息队列 windows系统是通过消息驱动的,每移动一下鼠标,点击一下屏幕都会产生一个消息.这些消息会先被放在windows的一个系统消息队列(先进先出)中,windows系统会为每一个GUI线程创建 ...

  5. Windows进程间通讯(IPC)----共享内存

    Windows中同一个EXE文件多次加载过程 Windows中EXE文件加载是基于内存映射文件的. 当EXE文件第一次被加载. 首先系统会先创建一个进程内核对象,并创建一个新的进程地址空间. 系统调用 ...

  6. Windows进程间通讯(IPC)----内存映射文件

    内存映射文件原理 内存映射文件是通过在虚拟地址空间中预留一块区域,然后通过从磁盘中已存在的文件为其调度物理存储器,访问此虚拟内存空间就相当于访问此磁盘文件了. 内存映射文件实现过程 HANDLE hF ...

  7. Windows进程间通讯(IPC)----WM_COPYDATA

    WM_COPYDATA通讯思路 通过向其他进程的窗口过程发送WM_COPYDATA消息可以实现进程间通讯. 只能通过SendMessage发送WM_COPYDATA消息,而不能通过PostMessag ...

  8. 服务 远程服务 AIDL 进程间通讯 IPC

    Activity aidl接口文件 package com.bqt.aidlservice;  interface IBinderInterface {     /* 更改文件后缀为[.aidl]去掉 ...

  9. Windows进程间通讯(IPC)----信号量

    线程同步内核对象 操作系统进行进程间同步是利用信号量机制.对于windows系统而言,可以利用一些内核对象进行线程同步,因为这些内核对象可以命名并且属于系统内核,所以可以支持不同进程间的线程同步进而实 ...

随机推荐

  1. 在 .NET Core 中构建 REST API

    翻译自 Camilo Reyes 2020年8月26日的文章 <Build a REST API in .NET Core> [1] REST API 可以使用简单的动词(如 POST.P ...

  2. PTA 单链表分段逆转

    6-9 单链表分段逆转 (25 分)   给定一个带头结点的单链表和一个整数K,要求你将链表中的每K个结点做一次逆转.例如给定单链表 1→2→3→4→5→6 和 K=3,你需要将链表改造成 3→2→1 ...

  3. Git标签与别名

    code[class*="language-"], pre[class*="language-"] { color: rgba(51, 51, 51, 1); ...

  4. python基础(十):集合的使用(上)

    集合的作用 去重:把一个列表变成集合,就自动去重了. 关系测试:测试两组数据之前的交集.差集.并集等关系. 集合的特征 集合使用 set 表示: 集合也使用{ }表示, 与字典不同的是:字典中存储的是 ...

  5. lms微服务框架主机介绍

    目录 概念 .net的通用主机 .net的web主机 lms的业务主机类型 用于托管业务应用的普通主机 1. 创建一个应用台程序 2. 安装Silky.Lms.NormHost包 3. 注册LMS服务 ...

  6. PBRT阅读笔记——COLOR AND RADIOMETRY

    四个关键概念 Energy(Q)   每一个光子都有特定的波长并携带特定的能量:      其中c为光速,h为普朗克常量. Flux(Φ)   辐射通量,可以直观理解为功率.是能量对时间微分得到的   ...

  7. 死磕Spring之AOP篇 - Spring AOP自动代理(二)筛选合适的通知器

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  8. 使用numba加速python科学计算

    技术背景 python作为一门编程语言,有非常大的生态优势,但是其执行效率一直被人诟病.纯粹的python代码跑起来速度会非常的缓慢,因此很多对性能要求比较高的python库,需要用C++或者Fort ...

  9. 1057 Stack

    Stack is one of the most fundamental data structures, which is based on the principle of Last In Fir ...

  10. Git 常用命令总结,将会持续更新

    平常在windows电脑上使用Git Extensions 工具比较多,大部分的常用指令都可以通过点点点就可以完成.在mac电脑上的话使用sourcetree工具.但有时候也会直接通过git命令,很多 ...