参考一

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

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

匿名通道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:读句柄和写句柄.其原型如下:

BOOL CreatePipe(

PHANDLE hReadPipe,    //指向读句柄的指针

PHANDLE hWritePipe,   //指向写句柄的指针

LPSECURITY_ATTRIBUTES lpPipeAttributes,    //指向安全属性的指针

DWORD nSize    //管道大小,若为0则由系统决定

};

匿名管道不支持异步读写操作.

命名管道是在管道是在管道服务器和一台或多台管道客户机之间进行单向或双向通信的一种命名的管道.一个命名管道的所有实例共享同一个管道名,但是每一个实例均拥有独立的缓存和句柄,并且为客户-服务通信提供一个分离的管道.

命名管道可以在同一台计算机的不同进程之间或在跨越一个网络的不同计算机的不同进程间进行有连接的可靠数据通信,如果连接中断,连接双方都能立即收到连接断开的信息。

每一个命名管道都有一个唯一的名字,以区分存在于系统的命名对象列表中的其他命名管道.管道服务器在调用CreateNamedPipe()函数创建命名管道的一个或多个实例时为其指定了名称.对于管道客户机,则是在调用CreateFile()或CallNamedPipe()函数以连接一个命名管道实例时对管道名进行指定.命名管道对其标识采用UNC格式:

\\Server\\Pipe\[Path]Name

其中,第一部分\\Server指定了服务器的名字,命名管道服务就在此服务器创建,其字串部分可以为一个小数点(表示本机)、星号(当前网络字段)、域名或是一个真正的服务;第二部分是一个不可变化的的硬编码字串;第三部分\[Path]Name则使应用程序可以唯一定义及标识一个命名管道的名字,而且可以设置多级目录.

管道服务器首次调用CreateNamedPipe()函数时,使用nMaxInstance参数指定了能同时存在的管道实例的最大数目.服务器可以重复调用CreateNamedPipe()函数去创建管道新的实例,直至达到设定的最大实例数.下面给出CreateNamedPipe()的函数原型:

HANDLE CreateNamedPipe(

LPCTSTR lpName,    //指向管道名称的指针

DWORD dwOpenMode,  //管道打开模式

DWORD dwPipeMode,  //管道模式

DWORD nMaxInstance,    //最大实例数

DWORD nOutBufferSize,  //输出缓存大小

DWORD nInBufferSize,   //输入缓存大小

DWORD nDefaultTimeOut,    //超时设置

LPSECURITY_ATTRIBUTES lpSecurityAttributes    //安全属性指针

};

其中,dwOpenMode参数用来指示管道在创建好之后,它的传输方向、I/O控制以及安全模式。

命名管道:可用于网络通信;可通过名称引用;支持多客户端连接;支持双向通信;支持异步重叠I/O;
匿名管道:只能本地使用。

参考二

操作系统中负责线程间通讯的东西叫管道。

管道(pipe)是进程用来通讯的共享内存区域。一个进程往管道中写入信息,而其它的进程可以从管道中读出信息。如其名,管道是进程间数据交流的通道。邮路(Mailslots)的功能与管道类似,也是进程间通讯(interprocess communications,IPC)的媒介,只不过其具体实现方式与管道有些差别。一个基于Win32的应用程序可以在邮路中储存消息,这些消息通常通过网络发往一个指定的计算机或某域名(域是共享一个组名的一组工作站或服务器。)下的所有计算机。你也可以使用命名管道代替邮路来进行进程间通信。命名管道最适合用来两个进程间的消息传递,邮路则更适合一个进程向多个进程广播消息。邮路具有一个重要的特点,它使用数据包广播消息。广播(broadcast)是网络传输中使用的术语,它意味着接收方收到数据后不发送确认消息通知发送方。而管道(这里的管道指命名管道,有关命名管道以下详解。)则不同,它更类似于打电话,你只对一个当事人说话,但是你却非常清楚你的话都被对方听到。邮路和管道一样,也是一个虚拟文件,它保存在内存中,但是你却必须使用普通的Win32文件函数访问它,比如CreateFile、ReadFile、WriteFile等。邮路中储存的数据可以是任何形式的,唯一的要求是不得超过64K。与磁盘文件不同的是,邮路是一个临时的对象,当某个邮路所有的句柄都关闭的时候,该邮路及其中的数据就被删除。

管道的类型有两种:匿名管道和命名管道。匿名管道是不命名的,它最初用于在本地系统中父进程与它启动的子进程之间的通信。命名管道更高级,它由一个名字来标识,以使客户端和服务端应用程序可以通过它进行彼此通信。而且,Win32命名管道甚至可以在不同系统的进程间使用,这使它成为许多客户/服务器应用程序的理想之选。

就像水管连接两个地方并输送水一样,软件的管道连接两个进程并输送数据。一个一个管道一旦被建立,它就可以象文件一样被访问,并且可以使用许多与文件操作同样的函数。可以使用CreateFile函数获取一个已打开的管道的句柄,或者由另一个进程提供一个句柄。使用WriteFile函数向管道写入数据,之后这些数据可以被另外的进程用ReadFile函数读取。管道是系统对象,因此管道的句柄在不需要时必须使用CloseHandle函数关闭。

匿名管道只能单向传送数据,而命名管道可以双向传送。管道可以以比特流形式传送任意数量的数据。命名管道还可以将数据集合到称为消息的数据块中。命名管道甚至具有通过网络连接多进程的能力。但遗憾的是Windows9X不支持创建命名管道,它只能在WindowsNT系列(如Windows NT,Windows 2000,Windows XP)的操作系统上创建。

当讨论管道时,通常涉及到两个进程:客户进程和服务进程。服务进程负责创建管道。客户进程连接到管道。服务进程可以创建一个管道的多个实例,以此支持多个客户进程。

参考三

一、概述

  管道(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操作。

实例代码

客户端源码

#include <windows.h>
#include <iostream>
using namespace std;
const TCHAR szPipeName[] = "\\\\.\\pipe\\potok";
int main(void)
{
HANDLE hPipe = CreateFile(szPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hPipe == INVALID_HANDLE_VALUE)
{
printf("CreateFile return [%d]!\n", GetLastError());
return -1;
}
DWORD dwRead, dwWrite;
char szBuf[1024] = {0};
for (int i = 0; i < 10; ++i)
{
sprintf(szBuf, "%d", i);
WriteFile(hPipe, szBuf, strlen(szBuf), &dwWrite, 0);
printf("Send: %s\n", szBuf);
memset(szBuf, 0, sizeof(szBuf));
ReadFile(hPipe, szBuf, sizeof(szBuf), &dwRead, 0);
printf("Recv: %s\n", szBuf);
}
system("pause");
return 0;
}

服务器端源码

#include <iostream>
#include <Windows.h>
using namespace std;
int main(void)
{
TCHAR strPipeName[] = "\\\\.\\pipe\\potok";
PSECURITY_DESCRIPTOR psd;
psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
{
LocalFree((HLOCAL)psd);
return -1;
}
if (!SetSecurityDescriptorDacl(psd, TRUE, (PACL)NULL, FALSE))
{
LocalFree((HLOCAL)psd);
return -1;
}
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength =sizeof(SECURITY_ATTRIBUTES);
saAttr.lpSecurityDescriptor = psd;
saAttr.bInheritHandle = TRUE;
HANDLE hIPC = CreateNamedPipe(strPipeName,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1, 0, 0, 10000, &saAttr);
if (hIPC == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe return [%d]!\n", GetLastError());
return -1;
}
char szBuf[1024] = {0};
DWORD dwRead, dwWrite;
char szWrite[] = "Get You\n";
ConnectNamedPipe(hIPC, NULL);
while(1)
{
if (!ReadFile(hIPC, szBuf, sizeof(szBuf), &dwRead, 0))
{
break;
}
printf("%s\n", szBuf);
memset(szBuf, 0, sizeof(szBuf));
if (!WriteFile(hIPC, szWrite, strlen(szWrite), &dwWrite, NULL))
{
break;
}
}
return 0;
};

匿名管道 与 命名管道相关推荐

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

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

  2. Linux IPC:匿名管道 与 命名管道

    目录 一.管道的理解 二.匿名管道 三.命名管道 四.管道的通信流程 五.管道的特性   进程间通信方式有多种,本文介绍的是管道,管道分为匿名管道和命名管道. 一.管道的理解   生活中的管道用来传输 ...

  3. 【Linux】进程间通信--管道(匿名管道和命名管道)

    文章目录 前言 进程间通信的目的 管道 匿名管道 管道特点 站在文件描述符角度理解管道 匿名管道通信读写特点 命名管道 命名管道的原理 命名管道的创建 命名管道完成两个不同进程通信 匿名管道和命名管道 ...

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

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

  5. 进程间通信之管道(匿名管道与命名管道)

    进程间通信之管道 进程间通信 管道 什么是管道 管道分类--1.匿名管道 匿名管道举例 管道的特点 管道分类--2.命名管道 创建一个命名管道 举例 命名管道的打开规则 匿名管道与命名管道的区别 具体 ...

  6. python 命名管道_命名管道实践

    命名管道技术实验 管道介绍 管道(Pipe)是一种进程间的通信机制,Windows.Linux和UNIX都使用这种机制. 管道是通过I/O接口存取的字节流创建管道后,通过使用操作系统的任何读或写I/O ...

  7. java 命名管道_linux 命名管道实例详解

    linux进程间通信--命名管道 FIFO(命名管道)不同于匿名管道之处在于它提供⼀个路径名与之关联,以FIFO的⽂件形式存储于⽂件系统中.命名管道是⼀个设备⽂件,因此,即使进程与创建FIFO的进程不 ...

  8. C# 管道通信-命名管道(一)

    最近在做一个应用程序,涉及到两个应用程序之间的通讯,就想到了用C#的命名管道的方式来实现,经过一番小折腾,总算实现了,现把一些主体的代码粘贴出来与大家分享: 管道通讯会涉及到client端和Serve ...

  9. 进程间通信:管道和命名管道(FIFO)

    目录 概述 IPC 对象的持续性 什么是管道 读取外部程序的输出 将输出送往 popen 传递更多的数据 如何实现 popen pipe 调用 跨越 fork 调用管道 父进程和子进程 管道关闭后的读 ...

  10. 进程间的通信IPC(无名管道和命名管道)

    进程间的通信IPC介绍 进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息. IPC的方式通常有管道(包括无名管道和命名管道).消息队列.信号量 ...

最新文章

  1. 刷新aspx页面的六种方法
  2. 另类设计:12个基于桌面视图的网页设计作品
  3. ubuntu修改根用户密码
  4. LeetCode题组:第836题-矩形叠加
  5. lua调用.so测试
  6. php绘图效率,对于PHP绘图技术的理解
  7. Linux下使用NTFS格式移动硬盘
  8. 余弦信号频谱表达式_信号傅里叶变换系列文章(1):傅里叶级数、傅里叶系数以及傅里叶变换...
  9. 探究foreach对于迭代变量的封装性的研究
  10. C++语言引用的介绍和示例
  11. hbase 协处理器 部署_hbase协处理器概念及知识点总结
  12. 一步一步学习Servlet之ServletContext对象
  13. 2021-2025年中国电子液体处理系统行业市场供需与战略研究报告
  14. WinForm播放视频
  15. 2019春第四次课程设计实验报告
  16. R语言统计入门第六章——回归与相关性
  17. 无线网卡m2 ngff keyakeye接口改转多口有线网卡实现软路由
  18. 流利说AI刘扬:从教授到”AI虚拟老师“
  19. Container is running beyond physical memory limits
  20. 解决记事本写java时出现中文乱码问题

热门文章

  1. 2020届 中国农业银行 研发中心 武汉研发部 校招 (面经)
  2. 飞凌单片机解密_干货:芯片解密方法大全
  3. Phase2 Day13 MyHashMap
  4. Oracle 10g安装 (Windows平台)
  5. SSM汽车销售平台的设计与实现毕业设计源码171619
  6. Hibernate 下载、安装和使用
  7. 【转载】财务主管的ERP实施之路
  8. windows server 2000系统安装
  9. 狮子鱼社区团购商城系统小程序v17.7.0独立版+前端 安装使用教程
  10. html 透明玻璃效果图,CSS3教程实现模糊透明玻璃效果