進程間通訊:管道

任務:實現一個類bash的管道符功能程序,能夠經過特殊符號例如‘@’將第一個程序的輸出做爲第二個程序的輸入。html

大致思路:linux

1. 主進程建立一個管道,獲得一對讀寫fd[2],其中fd[0]用於讀,fd[1]用於寫。centos

2. fork子進程1,經過dup2將子進程的標準輸出改成fd[1],而後經過execve執行第一個程序;bash

3. fork子進程2,經過dup2將子進程的標準輸入改成fd[0],而後經過execve執行第二個程序;centos7

4. 主進程等待子進程執行結束後退出。spa

參考文檔:code

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

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

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
相關文章
相關標籤/搜索