匿名和命名管道(windows)

来源:互联网 发布:淘宝装米礼品盒 编辑:程序博客网 时间:2024/06/04 18:16

一、概述

  管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种没有名字的管道,只能在本地计算机中使用,而不可用于网络间的通信。

二、匿名管道

  匿名管道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:管道读句柄和管道写句柄。CreatePipe()的函数原型为: 
 
BOOL CreatePipe(PHANDLE hReadPipe,                      // 指向读句柄的指针
  PHANDLE hWritePipe,                     // 指向写句柄的指针
  LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全属性的指针
  DWORD nSize                             // 管道大小
  );

如果函数成功返回TRUE,否则返回FALSE,可以使用GetLastError()得到错误值。
其中,第3个参数的定义为:

typedef struct _SECURITY_ATTRIBUTES{
    DWORD  nLength;               // 本结构的字节数
    LPVOID lpSecurityDescriptor;  // 安全描述符地址
    BOOL   bInheritHandle;        // 是否可以被子进程继承
}SECURITY_ATTRIBUTES;

这个结构包含了一个对象的安全描述信息,并且指定了管道是否可以被自进程继承。

  通过hReadPipe和hWritePipe所指向的句柄可分别以只读、只写的方式去访问管道。但是在同一个进程中去读写管道是没有意义的,我们常常需要的是在父子进程中传递数据,也就是父写数据,子读数据,或者子写数据,子读数据。我们这里仅讨论后一种情况,一个典型是示例就是一个有窗口的程序调用控制台程序,把控制台的输出信息在父窗口中输出。

    当父进程执行CreateProcess()启动子进程时,系统会检查父进程内可以继承的内核对象句柄,复制到子进程空间,这样子进程就有了和父进程一样的匿名管道句柄,子进程对管道的写端放入数据,父进程就可以从读端取到数据。同样,父进程在写端放入数据,子进程也可以从读端取出数据。也就是说,一个匿名管道同时拥有了两个写端和读端。当父子进程任何一个关闭的时候,无论时候显式的关闭读写句柄,系统都会帮进程关闭所拥有的管道句柄。正常情况下,控制台进程的输输入出是在控制台窗口的,但是如果我们在创建子进程的时候指定了其输入输出,那么子进程就会从我们的管道读数据,把输出数据写到我们指定的管道。CreateProcess()定义如下:

BOOL CreateProcess(
    LPCTSTR  lpApplicationName,                 // 执行程序的名字
    LPTSTR  lpCommandLine,                 // 命令行字符串
    LPSECURITY_ATTRIBUTES  lpProcessAttributes, // 进程的安全属性的指针
    LPSECURITY_ATTRIBUTES  lpThreadAttributes, // 主线程安全属性指针
    BOOL  bInheritHandles,                 // 是否继承父进程句柄的标志
    DWORD  dwCreationFlags,                 // 创建时候的标志位
    LPVOID  lpEnvironment,                 // 环境变量块指针
    LPCTSTR  lpCurrentDirectory,         // 指定工作目录的字符串指针
    LPSTARTUPINFO  lpStartupInfo,         // 启动信息指针
    LPPROCESS_INFORMATION  lpProcessInformation // 进程信息指针
   );

    其中我们关心的启动信息结构,其定义为:
typedef struct _STARTUPINFO {    // si
    DWORD   cb;                  // 本结构体字节数,用于版本控制
    LPTSTR  lpReserved;
    LPTSTR  lpDesktop;
    LPTSTR  lpTitle;
    DWORD   dwX;
    DWORD   dwY;
    DWORD   dwXSize;
    DWORD   dwYSize;
    DWORD   dwXCountChars;
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;
    DWORD   dwFlags;
    WORD    wShowWindow;
    WORD    cbReserved2;
    LPBYTE  lpReserved2;
    HANDLE  hStdInput;          // 输入句柄
    HANDLE  hStdOutput;         // 输出句柄
    HANDLE  hStdError;          // 错误显示句柄
} STARTUPINFO, *LPSTARTUPINFO; 

    在创建子进程时候,指定了子进程的输出管道,我们在管道另一端读取就可以了。那么存在一个问题,我们什么时候能知道子进程结束了,或者说不再写数据了呢?ReadFile()函数会阻塞到读到数据或者出错的后才会返回,也就是说当管道的所有写端都关闭的时候,读会出错,能够使函数在一个循环中返回,那么,我们应该在创建子进程后立即关闭父进程所拥有的写句柄,那么当子进程结束时候,读到0字节返回。

  同样的道理,在用WriteFile()函数向管道写入数据时,只有在向管道写完指定字节的数据后或是在有错误发生时函数才会返回。如管道缓冲已满而数据还没有写完,WriteFile()将要等到另一进程对管道中数据读取以释放出更多可用空间后才能够返回。管道服务器在调用CreatePipe()创建管道时以参数nSize对管道的缓冲大小作了设定。 匿名管道并不支持异步读、写操作,这也就意味着不能在匿名管道中使用ReadFileEx()和WriteFileEx(),而且ReadFile()和WriteFile()中的lpOverLapped参数也将被忽略。

具体的代码为:


三、命名管道

命名管道作为一种通信方法,有其独特的优越性,这主要表现在它不完全依赖于某一种协议,而是适用于任何协议——只要能够实现通信。
  命名管道具有很好的使用灵活性,表现在:
  1) 既可用于本地,又可用于网络。
  2) 可以通过它的名称而被引用。
  3) 支持多客户机连接。
  4) 支持双向通信。
  5) 支持异步重叠I/O操作。

 

 

 


 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小米2s开不了机怎么办充电闪红灯 寄快递写错地址但已经发货了怎么办 拼多多发货时快递公司写错了怎么办 千牛发货信息写错了怎么办 发货物流单电话写错了怎么办 顺丰寄电脑保价后电脑进水了怎么办 微销通分享小程序没有二维码怎么办 京东的东西退掉但是赠品怎么办 买手机7天不给退换怎么办 买的水果拒收了商家不退钱怎么办 京东第三方签收后退货怎么办 京东上买的第三方的鞋子退货怎么办 淘宝买家退货条码不符签收了怎么办 此苹果已丢失并被抹掉怎么办 苹果手机显示已丢失并被抹掉怎么办 手机在保修期内坏了售后拖延怎么办 微信图片在电脑上打印不清楚怎么办 遇到职业搞坏淘宝店铺的买家怎么办 眼破裂伤无光感半个月怎么办 出了虫的豆豆熬稀饭喝了怎么办? 果汁阳台月季叶子掉光了怎么办 近看好看远看难看该怎么办 衣服褶皱没有熨斗的情况下怎么办 裤子磨得发亮怎么办也没有电熨斗 老是在灯箱拍照对眼睛不好怎么办 电信光纤宽带账号密码忘记了怎么办 遇到尴尬的事情自己缓不过来怎么办 注销微信账号显示非法请求怎么办 微信备份以前的被覆盖了怎么办 之前微信号被新微信号覆盖了怎么办 微信发出的消息变成绿色怎么办 收了客户的资金被骗走了怎么办 淘宝退回去的衣服店家不接收怎么办 淘宝同款衣服价格相差很大该怎么办 淘宝买的衣服退回去了不退钱怎么办 淘宝客人退回的衣服有口红印怎么办 淘宝拍产品照片被投诉著作权怎么办 员工总在节假日忙的时候请假怎么办 买东西商家少给了货应该怎么办 买家退回的衣服有污渍卖家该怎么办 商家说衣服有污渍不退怎么办