Windows进程间通讯(IPC)----管道
管道的分类
管道其实际就是一段共享内存,只不过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)----管道的更多相关文章
- High Performance Networking in Google Chrome 进程间通讯(IPC) 多进程资源加载
小结: 1. 小文件存储于一个文件中: 在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里.其中有索引文件(在浏览器启动时加载到内存中),数据文件( ...
- Android AIDL 进行进程间通讯(IPC)
编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...
- QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开 本文地址:h ...
- Windows进程间通讯(IPC)----消息队列
消息队列 windows系统是通过消息驱动的,每移动一下鼠标,点击一下屏幕都会产生一个消息.这些消息会先被放在windows的一个系统消息队列(先进先出)中,windows系统会为每一个GUI线程创建 ...
- Windows进程间通讯(IPC)----共享内存
Windows中同一个EXE文件多次加载过程 Windows中EXE文件加载是基于内存映射文件的. 当EXE文件第一次被加载. 首先系统会先创建一个进程内核对象,并创建一个新的进程地址空间. 系统调用 ...
- Windows进程间通讯(IPC)----内存映射文件
内存映射文件原理 内存映射文件是通过在虚拟地址空间中预留一块区域,然后通过从磁盘中已存在的文件为其调度物理存储器,访问此虚拟内存空间就相当于访问此磁盘文件了. 内存映射文件实现过程 HANDLE hF ...
- Windows进程间通讯(IPC)----WM_COPYDATA
WM_COPYDATA通讯思路 通过向其他进程的窗口过程发送WM_COPYDATA消息可以实现进程间通讯. 只能通过SendMessage发送WM_COPYDATA消息,而不能通过PostMessag ...
- 服务 远程服务 AIDL 进程间通讯 IPC
Activity aidl接口文件 package com.bqt.aidlservice; interface IBinderInterface { /* 更改文件后缀为[.aidl]去掉 ...
- Windows进程间通讯(IPC)----信号量
线程同步内核对象 操作系统进行进程间同步是利用信号量机制.对于windows系统而言,可以利用一些内核对象进行线程同步,因为这些内核对象可以命名并且属于系统内核,所以可以支持不同进程间的线程同步进而实 ...
随机推荐
- 一种3位sar adc工作过程推导(二)
3位sar adc采用下图的电容阵列,需要23个电容,它的基本单元有二进制加权的电容阵列.1个与LSB电容等值的电容:它利用电容上的初始电荷再分配完成二进制搜索算法,因此功耗一般比较小,而且不需要额外 ...
- Python基础之异常定义
技术背景 在各类python的项目中,总会涉及到项目自身相关的一些约束条件.这些约束条件体现在,当用户输入的参数或者文件不符合项目要求时,就拒绝这个参数的输入并且播报出来,提醒用户自行修改,而这一过程 ...
- 第18 章 : Kubernetes 调度和资源管理
Kubernetes 调度和资源管理 这节课主要讲三部分的内容: Kubernetes 的调度过程: Kubernetes 的基础调度能力(资源调度.关系调度): Kubernetes 高级调度能力( ...
- $@ 与 $* 差在哪?-- Shell十三问<第九问>
$@ 与 $* 差在哪?-- Shell十三问<第九问> 要说 $@ 与 $* 之前,需得先从 shell script 的 positional parameter 谈起.我们都已经知道 ...
- .net 开源模板引擎jntemplate 教程:基础篇之在ASP.NET MVC中使用Jntemplate
在ASP.NET MVC 中使用Jntemplate 上一篇我们详细介绍了jntemplate的标签语法,本篇文章将继续介绍如何在ASP.NET MVC 中使用Jntemplate. 一.使用Jnte ...
- 痞子衡嵌入式:在i.MXRT启动头FDCB里调整Flash工作频率也需同步设Dummy Cycle
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是Flash工作频率与Dummy Cycle的联系. 上一篇文章 <从头开始认识i.MXRT启动头FDCB里的lookupTable ...
- JVM(三)类加载与字节码技术
1.类文件结构 首先获得.class字节码文件 方法: 在文本文档里写入java代码(文件名与类名一致),将文件类型改为.java 在文件对应目录下运行cmd,执行javac XXX.java 以下是 ...
- 【CTF】CTFHub 技能树 文件头检查 writeup
PHP一句话木马 <?php @eval($_POST["pass"]);?> <?php eval($_REQUEST["pass"]);? ...
- Mariadb3—多表查询
1.内关联 select 字段名 from 表名1 inner join 表名2 on 表名1.字段名=表名2.字段名 where 条件 2.左关联 select 字段名 from 表名1 left ...
- C++ new和delete运算符得简单使用
NEW C++ 中的new运算符用来分配内存,和c语言中得malloc有相似得功能. 使用new为当个元素开辟内存空间,并返回地址 typeName *pointer_name =new typeNa ...