Linux 管道

1.管道的基本概念

  管道是一种两个进程间进行单向通信的机制。当一个进程连接数据流到另一个进程时,我们使用术语管道(pipe)。

通常是把一个进程的输出通过管道连接到另外一个进程的输入。

2.pipe

  linux下管道由pipe系统调用函数创建,提供一个单向数据流。首先看一下它的原型

 #include <unistd.h>

 int pipe(int fildes[2]);

  函数参数为一个由两个整数类型的文件描述符组成的数组的指针,保存两个文件描述符。管道创建后,fildes[0]打开来读,fildes[1]打开来写。

创建成功函数返回0,失败返回-1并设置errno来表明失败的原因.

  两个返回的文件描述符以一种特殊的方式连接起来,写到fildes[1]的所有数据都可以从fildes[0]读回来。数据基于先进先出的原则。所以读到的

数据流顺序就是写入时的顺序。

  注意:我们操作管道时不时直接操作文件流,而是操作文件描述符。

  管道的优势在于可以在可以在两个进程之间传递数据,我们看一个父子进程通信的例子。

  

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

int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    char buffer[BUFSIZ + 1];
    pid_t fork_result;

    memset(buffer,'\0',sizeof(buffer));

    if(pipe(file_pipes) == 0)
    {
        fork_result = fork();
        if(fork_result == -1)
        {
            fprintf(stderr,"Fork failure");
        }
        if(fork_result == 0)
        {
            data_processed = read(file_pipes[0],buffer,BUFSIZ);
            printf("Read %d bytes: %bs\n",data_processed,buffer);
            exit(EXIT_SUCCESS);
        }
        else
        {
            data_processed = write(file_pipes[1],some_data,strlen(some_data));
            printf("Wrote %d bytes\n",data_processed);
        }
    }
    exit(EXIT_SUCCESS);
}

  该例来自于《Linux程序设计》13章第5节

执行./pipe

  Wrote 3 bytes

  Read 3 bytes: 123

3.管道与exec函数

  管道用于在两个进程之间进行单向通信,但是不能只限于父子间进程,我们使用exec函数替换子进程,实现任意进程

之间的管道通信。

  

//write_fork.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    int data_processed;
    int file_pipes[2];
    const char *some_data = "123";
    char buffer[BUFSIZ+1];
    pid_t fork_result;

    memset(buffer,'\0',sizeof(buffer));

    if(pipe(file_pipes) == 0)
    {
        fork_result = fork();
        if(fork_result == (pid_t)-1)
        {
            fprintf(stderr,"Fork failure");
            exit(EXIT_FAILURE);
        }
        if(fork_result == 0)
        {
            sprintf(buffer,"%d",file_pipes[0]);
            (void)execl("read_fork","read_fork",buffer,(char*)0);
            exit(EXIT_FAILURE);
        }
        else
        {
            data_processed = write(file_pipes[1],some_data,
                    strlen(some_data));
            printf("%d - wrote %d bytes\n",getpid(),data_processed);
        }
    }
    exit(EXIT_SUCCESS);
}
//read_fork.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc,char *argv[])
{
    int data_processed;
    char buffer[BUFSIZ + 1];
    int file_descriptor;

    memset(buffer,'\0',sizeof(buffer));
    sscanf(argv[1],"%d",&file_descriptor);
    data_processed = read(file_descriptor,buffer,BUFSIZ);

    printf("%d - read %d bytese: %s\n",getpid(),data_processed,buffer);
    exit(EXIT_SUCCESS);
}

  在进程read_fork中进程读操作,在write_fork中,将子进程替换为read_fork。

在write_fork进程中,将数据写入到fildes[1]中,将fildes[0]作为参数传给read_fork

的main函数的参数,在read_fork中,读出管道中的数据。

4.管道的读操作

  通常读取读取数据的程序并不知道有多少数据需要读取,所以常采用循环的方法读取数据,

当没有数据可以读取时,read调用通常会阻塞,即3他将暂停进程来等待直到有数据到达为止。

 

posted @ 2017-04-07 15:39  是召不是昭  阅读(396)  评论(0编辑  收藏  举报