一、管道
当从一个进程连接数据流到另一个进程时,我们使用术语管道(pipe)。我们通常是把一个进程的输出通过管道连接到另一个进程的输入。对于shell命令来说,命令的连接是通过管道字符来完成的,如:cmd1 | cmd2
1、进程管道
可能最简单的在两个程序之间传递数据的方法就是使用popen和pclose函数了,它们的原型如下:
#include<stdio.h> FILE *popen(const char *command,const char *open_mode); int pclose(FILE *stream_to_close);
popen函数允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或通过它接收数据。command字符串是要运行的程序名和相应的参数。open_mode必须是“r"或者“w”。这意味着我们不能调用另一个程序并同时对它进行读写操作。
2、pipe调用
pipe函数的原型如下:
#include<unistd.h> int pipe(int file_descriptor[2]);
pipe函数的参数是一个由两个整数类型的文件描述符组成的数组的指针。该函数在数组中填上两个新的文件描述符后返回0,如果失败则返回-1并设置errno来表明失败的原因。两个返回的文件描述符以一种特殊的方式连接起来。写到file_descriptor[1]的所有数据都可以从file_descriptor[0]读回来。数据基于先进先出的原则进行处理,这意味着如果把字节1,2,3写到file_descriptor[1],从file_descriptor[0]读到的数据也会是1,2,3。(这里使用的是文件描述符而不是文件流,所以我们必须用底层的read和write调用来访问数据,而不是用文件流库函数fread和fwrite。
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char* data; pid_t fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == (pid_t)0) { close(0); dup(file_pipes[0]); //close(file_pipes[0]); close(file_pipes[1]); read(file_pipes[0],data,8); printf("%s ",data); //execlp("od", "od", "-c", (char *)0); exit(EXIT_FAILURE); } else { close(file_pipes[0]); data_processed = write(file_pipes[1], some_data,strlen(some_data)); close(file_pipes[1]); printf("%d - wrote %d bytes ", (int)getpid(), data_processed); } } exit(EXIT_SUCCESS); }
运行后得到如下结果:
Wrote 3 bytes Read 3 bytes: 123
接下来,我们将学习如何在子进程中运行一个与其父进程完全不同的另外一个程序,而不是仅仅运行一个相同程序。我们用exec调用来完成这一工作。这里的一个难点是,通过exec调用的进程需要知道应该访问哪个文件描述符。在前面的例子中,因为子进程本身有file_pipes数据的一份副本,所以这并不成为问题。但经过exec调用后,情况就不一样了,因为原先的进程已经被新的子进程替换了。为了解决这个问题,我们可以将文件描述符(它实际上只是一个数字)作为一个参数传递给用exec启动的程序。
为了演示它是如何工作的,我们需要使用两个程序,第一个程序是数据生产者,它负责创建管道和启动子进程,而后者是数据消费者。
如下pipe3.c:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; pid_t fork_result; memset(buffer, '