上一篇《进程通信之二 管道技术第一篇 输入输出的重定向》示范了增加若干程序代码来完成程序输入输出的重定向,并提出了如果没有程序源代码,只有程序文件如何来完成重定向。本篇就介绍如何使用匿名管道来完成这一任务。

计算机中管道pipe类似于现实世界中的水管道,在一端放入水流,另一端就会流出来。在计算机机中水流自然被数据流所代替了。计算机中管道分为匿名管道和命名管道,本篇将主要介绍用匿名管道来完成这一重定向输出任务,命名管道就留给下一篇来介绍了。

先来看看如何创建和使用匿名管道。

第一个 CreatePipe

函数功能:创建管道

函数原型:

BOOLWINAPICreatePipe(

PHANDLEhReadPipe,

PHANDLEhWritePipe,

LPSECURITY_ATTRIBUTESlpPipeAttributes,

DWORDnSize

);

函数说明:

第一个参数返回新创建的管道的读取端句柄。

第二个参数返回新创建的管道的写入端句柄。

注意不能在管道的读取端写入数据也不能在写入端读取数据。

第三个参数表示管道的安全属性,通常可以作如下设置:

SECURITY_ATTRIBUTES sa;

sa.nLength             = sizeof(SECURITY_ATTRIBUTES);

sa.lpSecurityDescriptor   = NULL;

sa.bInheritHandle       = TRUE;

第四个参数表示管道的缓冲区容量,为0表示使用默认大小。

函数执行成功返回TRUE,否则返回FALSE。

第二个 ReadFile

函数功能:从管道中读取数据

函数原型:

BOOLReadFile(

HANDLEhFile,

LPVOIDlpBuffer,

DWORDnNumberOfBytesToRead,

LPDWORDlpNumberOfBytesRead,

LPOVERLAPPEDlpOverlapped

);

函数说明:

第一个参数为句柄,可以是创建文件函数CreateFile()的返回值也可以是管道。

第二个参数是一个指向缓冲区的指针,函数将读取的数据写入该缓冲区。

第三个参数的表达非常好,光从名字上就可以知道这是用来指定读取的字节数。

第四个参数将返回实际读取到的字节数。

第五个参数是用于异步操作方面,一般传入NULL即可。

第三个 WriteFile

函数功能:向管道写入数据

函数原型:

BOOLWriteFile(

HANDLEhFile,

LPCVOIDlpBuffer,

DWORDnNumberOfBytesToWrite,

LPDWORDlpNumberOfBytesWritten,

LPOVERLAPPEDlpOverlapped

);

函数说明:

第一个参数为句柄,可以是创建文件函数CreateFile()的返回值也可以是管道。

第二个参数是一个指针,该指针指向待写入管道的数据。

第三个参数表示要写入的字节数。

第四个参数将返回实际写入管道的字节数。

第五个参数是用于异步操作方面,一般传入NULL即可。

第四个CloseHandle

函数功能:关闭管道的一端

函数原型:BOOLCloseHandle(HANDLEhObject);

函数说明:当读取和写入端都关闭后,系统会关闭管道并回收资源。

从后面三个函数可以看出,向管道中读取和写入数据就和向文件中读取和写入数据是一样的(事实上管道也是一种特殊的文件——内存映射文件)。

使用管道要注意的一个地方是:读取和写入数据时,一定要注意顺序,MSDN上说,如果管道中没有数据,调用ReadFile()会造成阻塞,直到有其它线程将数据写入管道。同样,当有线程正在管道中读取数据时,其它试图将数据写入管道的的线程也会被阻塞。

因此对上一篇的示例程序进行重定向时,可以先创建二个管道,一个用来存放输入数据,称为数据输入管道,另一个用来存放输出数据,称为数据输出管道。然后从输入文件中读取数据并写入数据输入管道。再启动示例程序作为子进程,子进程的输入输出已经改成从数据输入管道中读取和输出到数据输出管道。子进程运行结束后,从数据输出管道中将数据写入到输出文件即可。整个流程图如下所示:

下面给出使用管道的示例代码:

//用管道来完成子进程的重定向。
//流程如下:
// infile.txt -> Input管道 -> 标准程序.exe -> Output管道 -> outfile.txt
#include <windows.h>
#include <stdio.h>
int main()
{printf("   使用管道来重定向子进程的输入输出\n");  printf("  --by MoreWindows( http://blog.csdn.net/MoreWindows )--\n\n"); char sz[3][50] = {"示例程序.exe", "infile.txt", "outfile.txt"};HANDLE hPipeInputRead, hPipeInputWrite, hPipeOutputRead, hPipeOutputWrite;//创建两个管道SECURITY_ATTRIBUTES sa;  sa.nLength              = sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor = NULL;sa.bInheritHandle       = TRUE;//数据输入管道CreatePipe(&hPipeInputRead, &hPipeInputWrite, &sa, 0);//数据输出管道CreatePipe(&hPipeOutputRead, &hPipeOutputWrite, &sa, 0);printf("创建数据输入管道和数据输出管道完毕\n");//从文件中读取数据,写入管道ReadFile中.const int BUFSIZE  = 4096;CHAR chBuf[BUFSIZE] = {0}; DWORD dwRead, dwWritten;BOOL  fSuccess;HANDLE hInputFile = CreateFile(sz[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);while (true) {//从文件中读取数据fSuccess = ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL);if (!fSuccess || dwRead == 0)break; //将数据写入管道fSuccess = WriteFile(hPipeInputWrite, chBuf, dwRead, &dwWritten, NULL);if (!fSuccess) break; } //关闭输入数据管道CloseHandle(hInputFile);hInputFile = NULL;CloseHandle(hPipeInputWrite);hPipeInputWrite = NULL;printf("已经从文件中读取数据并写入数据输入管道\n");printf("启动示例程序并重定向到管道中\n....\n");//启动示例程序作为子进程STARTUPINFO si;si.cb = sizeof(STARTUPINFO);GetStartupInfo(&si); si.hStdInput   = hPipeInputRead;   //输入由标准输入 -> 从管道中读取si.hStdOutput  = hPipeOutputWrite; //输出由标准输出 -> 输出到管道si.wShowWindow = SW_HIDE;  si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;  PROCESS_INFORMATION pi; CreateProcess( sz[0], NULL, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);WaitForSingleObject(pi.hProcess, INFINITE);//关闭输入数据管道CloseHandle(hPipeInputRead);hPipeInputRead = NULL;CloseHandle(hPipeOutputWrite);hPipeOutputWrite = NULL;printf("示例程序完成处理,现在将数据输出管道中的数据写入文件\n");//将输出数据管道中的数据写入到文件中HANDLE hOutputFile = CreateFile(sz[2], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); while (true){ //从管道中读取fSuccess = ReadFile(hPipeOutputRead, chBuf, BUFSIZE, &dwRead, NULL);if( !fSuccess || dwRead == 0) break; //写入输出文件fSuccess = WriteFile(hOutputFile, chBuf, dwRead, &dwWritten, NULL);if (!fSuccess) break; } //关闭输出数据管道CloseHandle(hOutputFile);hOutputFile = NULL;CloseHandle(hPipeOutputRead);hPipeOutputRead = NULL;printf("数据输出管道中的数据写入文件完毕\n");return 0;
}

运行结果如下图:

结果完全正确,说明我们的程序已经完成了启动其它程序并对它进行重定向这一功能。

对匿名管道总结一下:匿名管道有读取端和写入端。匿名管道创建(CreatePipe)后就可以像读写文件一样的对管道中的数据读写(ReadFileWriteFile),但要注意读写顺序。匿名管道在关闭两端后会由系统销毁并回收资源。

匿名管道的使用比较常见,下面是二个安装程序的截图。

QQ游戏的安装过程截图:

五笔编码及时查的安装过程截图:

对比下这二个截图,显示的内容都差不多,都是解压缩文件并移动到指定地方。唯一不同的是一个是控制台界面,另一个是图形界面。联想上面的程序,不难得知QQ游戏的安装实际也是使用管道将一个控制台程序的输出内容显示到图形界面,这样既美观又便于维护。

下一篇《进程通信之二 管道技术第三篇 命名管道》将介绍命名管道的使用,欢迎参阅。

注:不知道程序代码的情况下还可以使用批处理来完成。批处理使用>和<来重定向,>为输出到文件,如果文件不存在就创建,已存在就清空原文件后再写入,<为从文件读取。批处理文件的内容可以这样写:

@echo off

<infile.txt 标准程序.exe >outfile.txt

也可以这样写:

@echo off

标准程序.exe <infile.txt >outfile.txt

批处理重定向的内部实现原理当然也是使用匿名管道。

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/7390441

如果觉得本文对您有帮助,请点击‘顶’支持一下,您的支持是我写作最大的动力,谢谢。

转载于:https://www.cnblogs.com/long12365/p/9731284.html

进程通信之二 管道技术第二篇 匿名管道相关推荐

  1. Liunx系统编程篇—进程通信(二)无名管道(原理、创建、实战)命名管道(原理、创建、实战)

    一.无名管道 管道,通常指无名管道(之所以叫无名管道是因为,没有文件名),是 UNIX 系统IPC最古老的形式. 特点 (1)它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端. (2) ...

  2. 红蓝对抗之隧道技术第二篇(reGeorg内网穿透、SSH隧道本地Socks代理、SSH远程转发、Earthworm Socks5代理、Tunna正向代理、ICMP隧道、DNS隧道、Frp穿透)

    文章目录 隧道应用 reGeorg内网穿透 SSH本地转发(正向) 场景一 场景二 SSH远程转发(反向) Earthworm Socks5代理 正向代理 反向代理 Tunna正向代理 ICMP隧道 ...

  3. 操作系统8-死锁和进程通信----(库函数scanf和printf是基于管道读写实现的!

    大纲: 死锁概念及死锁处理方法 银行家算法 死锁检测 进程通信方法:信号.管道.消息队列.共享内存 一.死锁 背景 可重用资源:资源不能被删除且任何时刻只能有一个进程使用,进程释放资源后其他进程可重用 ...

  4. 管道的概念(匿名管道)

    管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递.调用pipe系统函数即可创建一个管道.管道有如下特质:1.其本质是一个伪文件(实为内核缓冲区),伪文件即不是真正的文件,不占用磁 ...

  5. 攻防技术第二篇之-知己(防御手段)

    文章目录 攻防演练 POC Payload EXP 浏览器爬虫 反连平台 Fuzz 主动扫描 被动扫描 语义分析 业务建模 流量拦截 用户枚举 插件 访问控制列表ACL cookie防护 BOT防护 ...

  6. 进程通信:匿名管道和命名管道

    一.进程间通信方式 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. 有名管道 (named pipe) : ...

  7. (王道408考研操作系统)第二章进程管理-第一节4:进程通信(配合Linux)

    文章目录 一:什么是进程通信 二:如何实现进程间通信及其分类 三:通信方式1-共享存储(共享内存) (1)课本基础内容 (2)补充-Linux中的进程通信 四:通信方式2-管道 (1)管道是什么 (2 ...

  8. Linux进程通信(一)——pipe管道

    本章内容 采用pipe管道如何进行进程之间的通信 pipe管道进程通信的规则和限制 Linux中pipe管道的实现机制和管理pipe管道的结构体 什么是进程通信 进程通信就是两个进程之间进行数据交换, ...

  9. Linux进程通信——匿名管道、命名管道、管道的特性和共享内存

    Linux进程通信--匿名管道.命名管道.管道的特性和共享内存 一.管道 1.1 什么是管道? 1.2 匿名管道 <1> 匿名管道参数说明 <2> fork共享管道原理 < ...

最新文章

  1. 慕课网基于ElasticSearch的找房网实战开发企业级房屋搜索网项目学习心得(一)
  2. day02 cssjs 基础
  3. 利用Kickstart安装的方法
  4. 让产品自己召唤人——马化腾
  5. iPhone开发环境搭建For PC
  6. 考虑页面置换算法,系统有m个物理块供调度,初始时全空,页面引用串长度为p,包含了n个不同的页号,无论用什么算法,缺页次数不会少于( )
  7. java泛型(一)、泛型的基本介绍和使用
  8. 装逼的翻译,害死多少人,你同意吗?到底什么是非终止状态,终止状态
  9. linux修改语言环境
  10. 简直要逆天!超炫的 HTML5 粒子效果进度条
  11. 中国移动公布2019年智能家庭网关集采结果:华为、中兴中标
  12. 2015计算机考研重点,2015考研计算机复习:数据结构重点归纳_跨考网
  13. python和java选择哪个-Java、Python你会选择哪个?老男孩python
  14. SDUT_2012省赛选拔赛2 部分题目
  15. 后台返回数据时,接口设计规范参考
  16. opencv读取文件路径
  17. phpwind升级php7,【原创文章】升级phpwind为https
  18. CxImage使用介绍
  19. 计算机病毒的特点五笔怎么打,电脑有极品五笔的朋友,特别是WIN7的,请删除这个输入法,有病毒...
  20. 视频教程-思科CCNP专题系列⑨:交换机安全-思科认证

热门文章

  1. hihocoder 网络流二·最大流最小割定理
  2. jquery-ui里日期插件的使用
  3. 代码练习 用户注册登陆与密码加密
  4. FormShortCut MainForm 和 二级FORM
  5. ABAP-小技巧/知识(1)
  6. jQuery源码分析系列
  7. Source Insight 格式化
  8. python 面向对象(三大特性)
  9. [转]JS设计模式-单例模式(二)
  10. 斯坦福-随机图模型-week1.0_