linux系统编程之管道(一):匿名管道(pipe)

一,什么是管道

管道是Linux支持的最初Unix IPC形式之一,具备如下特色: html

  • 管道是半双工的,数据只能向一个方向流动;须要双方通讯时,须要创建起两个管道;
  • 只能用于父子进程或者兄弟进程之间(具备亲缘关系的进程);
  • 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,而且只存在与内存中。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另外一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,而且每次都是从缓冲区的头部读出数据。

管道的实现机制:linux

    管道是由内核管理的一个缓冲区,至关于咱们放入内存中的一个纸条。管道的一端链接一个进程的输出。这个进程会向管道中放入信息。管道的另外一端链接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不须要很大,它被设计成为环形的数据结构,以便管道能够被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另外一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另外一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。数组

二,管道的建立(pipe)

包含头文件<unistd.h> 数据结构

功能:建立一无名管道 函数

原型: spa

int pipe(int fd[2]); 设计

参数: 3d

fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端 code

返回值:成功返回0,失败返回错误代码 htm

man帮助说明:

DESCRIPTION       

       pipe() creates a pipe, a unidirectional data channel that can be used
       for interprocess communication.  The array pipefd is used to return
       two file descriptors referring to the ends of the pipe.  pipefd[0]
       refers to the read end of the pipe.  pipefd[1] refers to the write
       end of the pipe.  Data written to the write end of the pipe is
       buffered by the kernel until it is read from the read end of the
       pipe.  For further details, see pipe(7).
 
该函数建立的管道的两端处于一个进程中间,在实际应 用中没有太大意义,所以,一个进程在由pipe()建立管道后,通常再fork一个子进程,而后经过管道实现父子进程间的通讯(所以也不难推出,只要两个 进程中存在亲缘关系,这里的亲缘关系指的是具备共同的祖先,均可以采用管道方式来进行通讯)。父子进程间具备相同的文件描述符,且指向同一个管道pipe,其余没有关系的进程不能得到pipe()产生的两个文件描述符,也就不能利用同一个管道进行通讯。
建立管道后示意图:
QQ截图20130715212929
 
三,利用管道进行父子进程间数据传输
示例一:子进程向管道中写数据,父进程从管道中读出数据
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        close(fds[0]);//子进程关闭读端
        write(fds[1],"hello",5);
        exit(EXIT_SUCCESS);
    }

    close(fds[1]);//父进程关闭写端
    char buf[10] = {0};
    read(fds[0],buf,10);
    printf("receive datas = %s\n",buf);
    return 0;
}

结果:

QQ截图20130715214531

示例二:利用管道实现ls |wc –w功能

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        
        dup2(fds[1],STDOUT_FILENO);//复制文件描述符且指定新复制的fd为标准输出
        close(fds[0]);//子进程关闭读端
        close(fds[1]);
        execlp("ls","ls",NULL);
        fprintf(stderr,"exec error\n");
        exit(EXIT_FAILURE);
    }

    dup2(fds[0],STDIN_FILENO);
    close(fds[1]);//父进程关闭写端
    close(fds[0]);
    execlp("wc","wc","-w",NULL);
    fprintf(stderr, "error execute wc\n");
    exit(EXIT_FAILURE);
}

结果:

QQ截图20130715215608

相关文章
相关标签/搜索