参考资料:
http://www.tldp.org/LDP/lpg/node11.html
http://blog.csdn.net/yeyuangen/article/details/6852682
http://blog.sina.com.cn/s/blog_65c5c5990100mx6d.html
管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。
下面是一个最简单的匿名管道的例子。
子进程中,先关闭管道的读出端,然后在管道的写端写入数据
在父进程中,先关闭管道的写入端,然后在管道的读出端读出数据。
int pipe( int fd[2] );
NOTES: fd[0] is set up for reading, fd[1] is set up for writing
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> int main(void) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n"; char readbuffer[80]; pipe(fd); if ((childpid = fork()) == -1) { perror("fork"); exit(1); } if (childpid == 0) { /* Child process closes up input side of pipe */ close( fd[0] ); /* Send "string" through the output side of pipe */ write(fd[1], string, (strlen(string)+1)); exit(0); } else { /* Parent process closes up output side of pipe */ close( fd[1] ); /* Read in a string from the pipe */ nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); if (nbytes != -1) { printf("Received string: %s", readbuffer); } } return(0); }
下面将dup跟管道结合其来使用。
在子进程中调用 dup2(fd[1], STDOUT_FILENO); 则printf("hello world\n");的数据就会写入到fd[1]中
在父进程中调用 dup2(fd[0], STDIN_FILENO); 则fgets(readbuffer, sizeof(readbuffer), stdin);会把fd[0]的数据读取出来。
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> int main(void) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n"; char readbuffer[80]; pipe(fd); if ((childpid = fork()) == -1) { perror("fork"); exit(1); } if (childpid == 0) { /* Child process closes up input side of pipe */ close( fd[0] ); /* Send "string" through the output side of pipe */ dup2(fd[1], STDOUT_FILENO); //write(fd[1], string, (strlen(string)+1)); printf("hello world\n"); fflush(stdout); exit(0); } else { /* Parent process closes up output side of pipe */ close( fd[1] ); /* Read in a string from the pipe */ dup2(fd[0], STDIN_FILENO); //nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); fgets(readbuffer, sizeof(readbuffer), stdin); if (nbytes != -1) { printf("from the stdin,Received string: %s", readbuffer); } } return(0); }
Often, the descriptors in the child are duplicated onto standard input or output. The child can then exec() another program, which inherits the standard streams. Let‘s look at the dup2() system call:
我们的子进程把它的输出重定向的管道的写端,然后,父进程将它的输入重定向到管道的读端
子进程关闭 管道读端 close( fd[0] ); 调用 dup2(fd[1], STDOUT_FILENO); 将管道的写端重定向到标准输出
父进程关闭 管道写端 close( fd[1] ); 调用 dup2(fd[0], STDIN_FILENO); 将管道的读端重定向到标准输入
The child can then exec() another program, which inherits the standard streams.
工作流程:
子进程调用 execlp( "ls", "ls", "-1", NULL ); ----> 标准输出----->管道的写端------->
管道的读端(父进程)------->标准输入---->execlp( "wc", "wc", "-l", NULL );
我们看到的结果是 ls -1|wc -l 的结果
管道命令的使用 :
第一条命令 | 第二条命令
将第一条命令的结果作为第二条命令的参数来使用
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> int main(void) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n"; char readbuffer[80]; pipe(fd); if ((childpid = fork()) == -1) { perror("fork"); exit(1); } if (childpid == 0) { /* Child process closes up input side of pipe */ close( fd[0] ); /* Send "string" through the output side of pipe */ dup2(fd[1], STDOUT_FILENO); execlp( "ls", "ls", "-1", NULL ); exit(0); } else { /* Parent process closes up output side of pipe */ close( fd[1] ); /* Read in a string from the pipe */ dup2(fd[0], STDIN_FILENO); execlp( "wc", "wc", "-l", NULL ); } return(0); }