进程间通信:管道

任务:实现一个类bash的管道符功能程序,可以通过特殊符号例如‘@’将第一个程序的输出作为第二个程序的输入。

大体思路:

1. 主进程创建一个管道,得到一对读写fd[2],其中fd[0]用于读,fd[1]用于写。

2. fork子进程1,通过dup2将子进程的标准输出改为fd[1],然后通过execve执行第一个程序;

3. fork子进程2,通过dup2将子进程的标准输入改为fd[0],然后通过execve执行第二个程序;

4. 主进程等待子进程执行结束后退出。

参考文档:

http://man7.org/linux/man-pages/man2/pipe.2.html

http://man7.org/linux/man-pages/man2/wait.2.html

http://man7.org/linux/man-pages/man2/fork.2.html

http://man7.org/linux/man-pages/man2/execve.2.html

http://man7.org/linux/man-pages/man2/dup2.2.html

代码实现:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>

int main(int argc, char* argv[]){
    int pipefd[2];
    pid_t cpid[2];
    int i,pargindex,pipeindex,res,wstate1,wstate2;
    char* environ[] = {NULL};

    if(argc < 2){
        fprintf(stderr,"Usage: %s <string> @ <string> ...\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    pargindex = 1;
    for(i=1;i < argc;++i){
        if(**(argv+i) == '@'){
            pipeindex = i;
            argv[i] = NULL;
            break;
        }
    }

    if (pipeindex > 0) {
        if (pipe(pipefd) == -1){
            perror("pipe error\n");
            exit(EXIT_FAILURE);
        }
        
        cpid[0] = fork();
        if(cpid[0] == -1){
            perror("fork fail.\n");
            exit(EXIT_FAILURE);
        }
        
        if (cpid[0] == 0){
            close(pipefd[0]);
            res = dup2(pipefd[1],STDOUT_FILENO);
            if(res == -1){
                perror("dup2 error\n");
                _exit(EXIT_FAILURE);
            }
            execve(argv[pargindex],argv + pargindex,environ);
            perror(argv[pargindex]);
            _exit(EXIT_FAILURE);
        }

        cpid[1] = fork();
        if (cpid[1] == -1){
            perror("fork 2 fail");
            exit(EXIT_FAILURE);
        }
        pargindex = pipeindex + 1;
        if (cpid[1] == 0){
            close(pipefd[1]);
            res = dup2(pipefd[0],STDIN_FILENO);
            if(res == -1){
                perror("dup2 stdin");
                _exit(EXIT_FAILURE);
            }
            execve(argv[pargindex],argv + pargindex,environ);
            perror(argv[pargindex]);
            _exit(EXIT_FAILURE);
        }

        close(pipefd[0]);
        close(pipefd[1]);
        
        if(waitpid(cpid[0],&wstate1,0) == -1){
            perror("waitpid 1");
        }

        write(pipefd[1],argv[0],strlen(argv[0]));
        if(waitpid(cpid[1],&wstate2,0) == -1){
            perror("waitpid 2");
        }
        
        exit(EXIT_SUCCESS);
    }

    execve(argv[pargindex],argv + pargindex,environ);
    perror(argv[pargindex]);
    exit(EXIT_FAILURE);
}

运行效果:

[root@centos7 c]# ./prog /usr/bin/cat prog.c @ /usr/bin/wc -l
90

 

posted @ 2019-03-08 14:59  zerofl-diary  阅读(276)  评论(0编辑  收藏  举报