管道(pipe)

1. 背景

有次遇到过这样的需求:应用程序A(自己可编码编译)调用一个控制台程序B(第三方的,不能修改),控制台程序B会在标准输出设备(类似命令行窗口)上打印出数据,应用程序A要获取这些数据,并对数据进行处理。

实现了该需求之后,总结了下实现的方法:“管道”和“重定向”。这里简要总结下“管道”的概念,重点介绍“匿名管道”。

2. 管道(pipe

管道(pipe)有两种:匿名管道(anonymous pipes)和命名管道(named pipes)。管道实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。

匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。

3. 匿名管道(anonymous pipes

匿名管道由CreatePipe函数创建,该函数在创建匿名管道的同时返回两个句柄:管道只读句柄和管道只写句柄。CreatePipe的函数原型为:

BOOL CreatePipe(

    PHANDLE hReadPipe,   // pointer to read handle

    PHANDLE hWritePipe,  // pointer to write handle

    LPSECURITY_ATTRIBUTES lpPipeAttributes, // pointer to security attributes

    DWORD nSize         // pipe size

);

通过hReadPipehWritePipe所指向的句柄可分别以只读、只写的方式去访问管道。在使用匿名管道通信时,服务器进程必须将其中的一个句柄传送给客户机进程。句柄的传递多通过继承来完成,服务器进程也允许这些句柄为子进程所继承。除此之外,进程也可以通过诸如DDE或共享内存等形式的进程间通信将句柄发送给与其不相关联的进程。

在用WriteFile函数向管道写入数据时,只有在向管道写完指定字节的数据后或是在有错误发生时函数才会返回。如管道缓冲已满而数据还没有写完,WriteFile将要等到另一进程对管道中数据读取以释放出更多可用空间后才能够返回。管道服务器在调用CreatePipe创建管道时以参数nSize对管道的缓冲大小作了设定。

匿名管道并不支持异步读、写操作,这也就意味着不能在匿名管道中使用ReadFileExWriteFileEx,而且ReadFileWriteFile中的lpOverLapped参数也将被忽略。匿名管道将在读、写句柄都被关闭后退出,也可以在进程中调用CloseHandle函数来关闭此句柄。

4. 管道句柄的继承性

管道服务器可以通过以下途径来控制匿名管道是否可以被继承:

◆在调用CreatePipe函数时,如果管道服务器将lpPipeAttributes 指向的SECURITY_ATTRIBUTES数据结构的数据成员bInheritHandle设置为TRUE,那么CreatePipe创建的管道读、写句柄将会被继承。

◆管道服务器可调用DuplicateHandle函数改变管道句柄的继承。管道服务器可以为一个可继承的管道句柄创建一个不可继承的副本或是为一个不可继承的管道句柄创建一个可继承的副本。

CreateProcess函数还可以使管道服务器有能力决定子进程对其可继承句柄是全部继承还是不继承。

在生成子进程之前,父进程首先调用Win32 API SetStdHandle使子进程、父进程可共用标准输入、标准输出和标准错误句柄。当父进程向子进程发送数据时,用SetStdHandle将管道的读句柄赋予标准输入句柄;在从子进程接收数据时,则用SetStdHandle将管道的写句柄赋予标准输出(或标准错误)句柄。然后,父进程可以调用进程创建函数CreateProcess生成子进程。如果父进程要发送数据到子进程,父进程可调用WriteFile将数据写入到管道(传递管道写句柄给函数),子进程则调用GetStdHandle取得管道的读句柄,将该句柄传入ReadFile后从管道读取数据。

如果是父进程从子进程读取数据,那么由子进程调用GetStdHandle取得管道的写入句柄,并调用WriteFile将数据写入到管道。然后,父进程调用ReadFile从管道读取出数据(传递管道读句柄给函数)。

When all write handles to the pipe are closed, the ReadFile function returns zero. It is important for the parent process to close its handle to the write end of the pipe before calling ReadFile. If this is not done, the ReadFile operation cannot return zero because the parent process has an open handle to the write end of the pipe.

The procedure for redirecting the standard input handle is similar to that for redirecting the standard output handle, except that the pipe's read handle is used as the child's standard input handle. In this case, the parent process must ensure that the child process does not inherit the pipe's write handle. If this is not done, the ReadFile operation performed by the child process cannot return zero because the child process has an open handle to the write end of the pipe.

5. 参考

以上内容主要参考MSDN帮助文档:MSDN Library Visual Studio 6.0 (CHS)。可以找到CreatePipe函数后,在菜单“查看”>“在目录中定位主题”,找到管道的详细说明。同时MSDN也提供了源码例子。


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值