Linux进程通信IPC--管道Pipe/Named Pipe

来源:互联网 发布:房产税 知乎 编辑:程序博客网 时间:2024/05/21 15:02

前言: Linux 进程通信系列文章是对工作中使用的技术进行描述总结,前两篇文章分别讲述了MessageQueue、SharedMemory的方式,同作为Linux 最初支持Unix IPC的方式之一,管道也是进程间通信常用的方式。

管道(Pipe)

管道Pipe是Linux进程间通信的常用方式之一,正如其名字,像一根管子一样把进程A的输出连接到另一个进程B的输入。管道是半双工的,数据只能向一个方向流动,如果需要双方通信时,则必须建立起两个管道。

这里写图片描述

管道实际上是存在于内存中的文件,对这个文件的操作要通过两个已经打开文件描述符file_descriptor(简称fd)进行,两个fd分别代表管道的两端:读端和写端。然而管道是一种特殊独立的文件,不属于某一种文件系统,有独立的文件系统和自己的数据结构。

管道根据适用范围分为:无名管道(Pipe)和命名管道(Named Pipe)。

  • 无名管道(Pipe)

无名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。在Linux系统中可以通过系统调用建立起一个单向的通信管道,这种关系只能由父进程来建立且是单向的,因此如果需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,一个进程向管道中写的内容被管道另一端的进程读出,管道传输遵循“先入先出”(FIFO)的规则,写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

  • 命名管道(Named Pipe)

命名管道克服了无名管道只能用于亲缘关系进程之间的缺陷。命名管道是建立在实际的磁盘介质或文件系统上而不是只存在于内存中,有自己名字的文件,它提供一个路径名与之关联,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。命名管道引入了一种新的文件类型—FIFO文件(遵循先进先出的原则),并以FIFO的文件形式存在于文件系统中。即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,实现了通过FIFO不相关的进程也能够交换数据。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。

管道API 函数

  • 无名管道Pipe
int pipe(int file_descriptor[2]);

系统调用后,两个返回的文件描述符fd[0]、fd[1]以一种特殊的方式连接起来。fd[1]用于写入数据,fd[0]用于读出数据,写到fd[1]的所有数据都可以fd[0]读出来,相关数据遵循先进先出的原则(简写FIFO)。

  • 命名管道Named Pipe
int mkfifo(const char *filename, mode_t mode);int mknode(const char *filename, mode_t mode|S_IFIFO,(dev_t)0);

mkfifo/mknode会依参数filename建立特殊的FIFO文件,该文件必须不存在,参数mode为该文件的权限。建立的FIFO文件其他进程都可以用读写一般文件的方式存取。

管道使用举例

  • 无名管道Pipe
int main(void){    int n;    int fd[2];    pid_t pid;    char line[MAXLINE];    if(pipe(fd)< 0){        //先建立管道得到一对文件描述符        exit(0);    }    if((pid = fork()) < 0)  //父进程把文件描述符复制给子进程        exit(1);    else if(pid > 0){       //父进程写        close(fd[0]);       //关闭读描述符        write(fd[1], "\nhello world\n", 14);    }    else{                   //子进程读        close(fd[1]);       //关闭写端        n = read(fd[0], line, MAXLINE);        write(STDOUT_FILENO, line, n);    }    exit(0);}
  • 命名管道Named Pipe
int main()  {      int res = mkfifo("/tmp/my_fifo", 0777);  //创建FIFO文件    if (res == 0)      {          printf("FIFO created/n");      }       exit(EXIT_SUCCESS);  }

FIFO文件创建后,即可进行读写操作。

0 0