管道

管道由pipe函数创建,提供一个单向数据流。pipe函数返回两个文件描述符:fd[0]与fd[1],前者打开来读,后者打开来写。
管道的典型用途是在父子进程之前提供进程间通信手段。首先,由父进程创建一个管道,然后调用fork创建子进程。如果父进程关闭管道的读出端,子进程关闭管道的写入端。在父子进程间就形成了一个单向数据流。
通常我们在shell中输入一个像下面的命令时:
cmd1 | cmd2 | cmd3
将会创建三个进程和其中的两个管道。将每个进程的读出端复制到相应进程的标准输入,把每个管道的写入端复制到相应进程的标准输出。

一个管道的实现例子,来源于UNIX 网络编程 卷二

#include    "unpipc.h"

void
client(int readfd, int writefd)
{
    size_t  len;
    ssize_t n;
    char    buff[MAXLINE];

        /* 4read pathname */
    Fgets(buff, MAXLINE, stdin);
    len = strlen(buff);     /* fgets() guarantees null byte at end */
    if (buff[len-1] == '\n')
        len--;              /* delete newline from fgets() */

        /* 4write pathname to IPC channel */
    Write(writefd, buff, len);

        /* 4read from IPC, write to standard output */
    while ( (n = Read(readfd, buff, MAXLINE)) > 0)
        Write(STDOUT_FILENO, buff, n);
}
#include    "unpipc.h"

void
server(int readfd, int writefd)
{
    int     fd;
    ssize_t n;
    char    buff[MAXLINE+1];

        /* 4read pathname from IPC channel */
    if ( (n = Read(readfd, buff, MAXLINE)) == 0)
        err_quit("end-of-file while reading pathname");
    buff[n] = '\0';     /* null terminate pathname */

    if ( (fd = open(buff, O_RDONLY)) < 0) {
            /* 4error: must tell client */
        snprintf(buff + n, sizeof(buff) - n, ": can't open, %s\n",
                 strerror(errno));
        n = strlen(buff);
        Write(writefd, buff, n);

    } else {
            /* 4open succeeded: copy file to IPC channel */
        while ( (n = Read(fd, buff, MAXLINE)) > 0)
            Write(writefd, buff, n);
        Close(fd);
    }
}
#include    "unpipc.h"

void    client(int, int), server(int, int);

int
main(int argc, char **argv)
{
    int     pipe1[2], pipe2[2];
    pid_t   childpid;

    Pipe(pipe1);    /* create two pipes */
    Pipe(pipe2);

    if ( (childpid = Fork()) == 0) {        /* child */
        Close(pipe1[1]);
        Close(pipe2[0]);

        server(pipe1[0], pipe2[1]);
        exit(0);
    }
        /* 4parent */
    Close(pipe1[0]);
    Close(pipe2[1]);

    client(pipe2[0], pipe1[1]);

    Waitpid(childpid, NULL, 0);     /* wait for child to terminate */
    exit(0);
}