IPC-管道(匿名管道)

来源:互联网 发布:苹果cms整合ck播放器 编辑:程序博客网 时间:2024/05/16 13:58

管道(Pipe),也被叫做匿名管道,是UNIX系统IPC的最古老、最基本的机制,所以UNIX系统都提供此种通信机制。管道有两个局限性:

  • 最开始它是半双工的(即数据只能在一个方向上流动)。现在,某些系统提供全双工管道,但是为了可移植性,我们应该假定系统不支持全双工。
  • 管道只能在具有血缘关系的两进程之间使用(兄弟进程、父子进程之类具有公共祖先的进程)。

管道是单向的、先进先出、无结构的字节流,它把一个进程的输出和另一个进程的输入连接在一起。

  • 在写进程在管道尾端写入数据,读进程在管道的首端读出数据。数据读出后其他读取进程都不能再读到这些数据。
  • 当进程试图读取一个空管道时,在另一个写入进程未写入数据之前,进程将一直阻塞。管道已经满时,进程再试图将数据写入管道,在别的读取进程没有读取数据之前,写入数据进程将阻塞。

管道的创建
管道基于文件描述符的通信方式,是通过调用pipe函数创建的。

#include<unistd.h>int pipe(int fd[2]);

调用pipe函数时在内核开辟一块缓冲区(称为管道),它有一个读端,一个写端,然后通过参数传出给用户程序两个文件描述符。fd[0]指向管道的读端,fd[1]指向管道的写端,就像标准输入0,标准输出1是一样的。所以管道在用户程序看起来就像是一个文件,对于它的读写也可以使用普通的read()和write()等函数。但是它不是普通的文件,并不属于其他任何文件系统,只存在于内核的内存空间中。向它读写数据其实是在读写内核缓冲区。
返回值:调用失败返回-1,成功返回0。
管道
管道创建步骤:
使用管道进行通信大致的步骤:
管道通信步骤

  1. 创建管道:父进程用pipe函数创建管道,得到两个指向管道的文件描述符。
  2. 创建子进程:然后父进程fork出一个子进程,子进程继承父进程的文件描述符,也得到两个指向管道的文件描述符。
  3. 确定管道的传输方向(谁是读端,谁是写端):这里父进程关闭读端fd[0],子进程关闭写端fd[1]。实现父进程向管道里写数据,子进程从管道里面读数据。这样就实现了父子进程之间的通信。
  4. 通信:在写进程中调用write()函数,在读进程中调用read()函数
  5. 关闭管道:用close()关闭管道相关文件按。
    运用实例:
    在父进程中写入”i am child!”然后在子进程中读取,并且打印出来。
#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>int main(){    pid_t id;    int fd[2];    int ret=pipe(fd);    if(ret<0)    {        printf("pipe error!\n");    }    if(id=fork()<0)    {        printf("fork error!\n");    }    else if(id>0)//father    {        close(fd[0]);        int i=0;        char* mesg=NULL;        while(i<100)        {            mesg="i am child!";            write(fd[1],mesg,strlen(mesg)+1);            sleep(1);            i++;        }        close(fd[1]);    }    else//child    {        close(fd[1]);        char mesg[100];        int j=0;        while(j<100)        {        ssize_t s=read(fd[0],mesg,sizeof(mesg));        mesg[s-1]='\0';        printf("%s\n",mesg);        j++;        }        close(fd[0]);    }    return 0;}

运行结果:
这里写图片描述

使用管道还有一些限制:
上面说过两个进程通过一个管道只能实现单项通信。比如上例,如果需要子进程写,父进程读就得另外开一个管道。
另外,需要注意有下面几点情况:

  • 当读一个写端已经被关闭的管道时,在管道中所有数据都被读取后,read返回0,表示文件结束。
  • 如果有指向管道写端的⽂件描述符没关闭(管道写端的引⽤计数⼤于0),⽽持有管道写端的 进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
  • 如果有指向管道读端的⽂件描述符没关闭(管道读端的引⽤计数⼤于0),⽽持有管道读端的 进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再 次write会阻塞,直到管道中有空位置了才写⼊数据并返回。