特殊文件——管道

管道与重定向


概述

对于一些需要进程间的协作来解决问题的场景,进程间的通信是必要的。而最简单的UNIX进程通信机制就是管道,他是由特殊文件表示的。调用者可以通过文件描述符fd[0]和fd[1]来访问它,从fd[1]写入的数据可以按照先进先出的顺序从fd[0]中读出。

文件描述符:在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

我们要明白,每个Unix进程(除了可能的守护进程)应均有三个标准的POSIX文件描述符,对应于三个标准流:

整数值 名称 <unistd.h>符号常量 <stdio.h>文件流
0 Standard input STDIN_FILENO stdin
1 Standard output STDOUT_FILENO stdout
2 Standard error STDERR_FILENO stderr

例如:$ls -l | head -5中,|就表示一个管道,ls的标准输出被通过中间通信缓冲区被“连接”到了head的标准输入中。
此命令执行过程的文件描述符表的状态

实现重定向

了解了文件描述符的概念后,我们就能利用dup2函数来实现重定向。下面我们来用c语言模拟$ls -l | head -5

源代码

#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
    pid_t child;
    int fd[2];

    if ((pipe(fd) == -1) || ((child = fork()) == -1)) {
        perror("Failed to fork.");
        return 1;
    }

    if (child == 0) {     /* 子进程 */ 
        if (dup2(fd[1], STDOUT_FILENO) == -1)
            perror("Failed to redirect stdout of ls");
        else if ((close(fd[0]) == -1) || (close(fd[1]) == -1))
            perror("Failed to close extra pipe descriptors on ls");
        else {
            execl("/bin/ls", "ls", "-l", NULL);
            perror("Failed to execute ls");
        }
    }

    /* 父进程 */ 
    if (dup2(fd[0], STDIN_FILENO) == -1)
        perror("Failed to redirect stdin of head");
    else if ((close(fd[0]) == -1) || (close(fd[1]) == -1))
        perror("Failed to close extra pipe descriptors on head");
    else {
        execl("/usr/bin/head", "head", "-5", NULL);
        perror("Failed to execute head");
    }
    return 0;
}

过程图示

fork函数在创建一个子进程时,子进程就会继承父进程的环境和上下文中的大部分内容的一份拷贝,包括信号状态调度参数文件描述符表。由于子进程在被创建时会收到父进程文件描述符表的一份拷贝,因此对于在创建子进程前就打开的文件来书,父进程和子进程将共享同一个文件的偏移量。
调用fork后,文件描述符表状态如下:
调用后的文件描述符表状态

两个dup2函数执行完毕后,文件描述符表的状态如下:
两个函数执行完毕后的文件描述符表状态

调用close完毕后,文件描述符表的状态如下:
两个函数执行完毕后的文件描述符表状态

编译运行

$ gcc redirect_demo.c
$ ./a.out
total 4888
-rwxrwxr-x  1 chris chris    8576 3月   5 21:23 a.out
drwxrwx--- 10 chris chris    4096 3月   5 21:23 ccls
-rw-rw-r--  1 chris chris     637 3月   5 21:23 coc-25627.vim
-rw-rw-r--  1 chris chris   25829 3月   5 15:06 coc-ultisnips-c7dd5acb3d1574c377e86b60ee637c3c.py
posted @ 2020-03-05 21:28  chrisynl  阅读(432)  评论(0编辑  收藏  举报