进程间通信:管道
任务:实现一个类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