Inter-Process Communication: Pipes
进程Pipes
可能最简单的方式在两个程序中传递数据是用popen和pclose函数。
#include <stdio.h>
FILE *popen(const char *command, const char *open_mode);
int pclose(FILE *stream_to_close);
popen
这个popen函数允许一个程序去调用另一个程序作为一个新进程去传递一个数据或接受一个数据。这个命令字符串就是需要运行的程序的名字,程序的参数是任意的。open_mode必有是"r"或"w".如果open_mode是"r",从被调用的程序的输出数据可以被调用程序使用并且可以被popen打开的FILE文件指针读取,只要使用标准的输入输出函数就可以读取。如果open_mode是"w",这个程序可以发送数据给被调用的程序去进行fwrite.这个别调用的程序使用标准输入流就可以读取到数据。
pclose
当以popen开始的进程结束后,可以使用pclose来关闭与之相关的文件流。当这个程序还是运行的时候pclose会一直等待这个进程结束。pclose函数通常返回有关进程文件流将要关闭的进程退出代码。如果调用进程在使用函数pclose之前就执行了等待状态,那么它的退出状态将会丢失因为被调用的进程已经完成并且pclose会返回-1,errno被设置成ECHILD.
Reading Output from an External Program
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;
memset(buffer, ‘/0’, sizeof(buffer));
read_fp = popen(“uname -a”, “r”);
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
if (chars_read > 0) {
printf(“Output was:-/n%s/n”, buffer);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
Sending Output to popen
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
FILE *write_fp;
char buffer[BUFSIZ + 1];
sprintf(buffer, “Once upon a time, there was.../n”);
write_fp = popen(“od -c”, “w”);
if (write_fp != NULL) {
fwrite(buffer, sizeof(char), strlen(buffer), write_fp);
pclose(write_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
The Pipe Call
我们已经见过高级的popen函数,现在我们继续看一下低级别的pipe函数。这个函数在两个进程中提供一个传递数据的手段,不需要使用一个shell去解释请求命令。她给了我们更多的控制权去读写数据。
#include <unistd.h>
int pipe(int file_descriptor[2]);
pipe有一个整数文件描述符2位数组。当这个数组装满两个文件描述符则返回0,如果失败则返回-1并且设置errno有关错误信息。错误定义如下:
❑ EMFILE: Too many file descriptors are in use by the process.
❑ ENFILE: The system file table is full.
❑ EFAULT: The file descriptor is not valid.
这两个文件描述符以一种特殊的方式链接,任何写进file_descriptor[1]的数据将从file_descriptor[0]读出来。通常把这种模式叫FIFO。
#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];
memset(buffer, ‘/0’, sizeof(buffer));
if (pipe(file_pipes) == 0) {
data_processed = write(file_pipes[1], some_data, strlen(some_data));
printf(“Wrote %d bytes/n”, data_processed);
data_processed = read(file_pipes[0], buffer, BUFSIZ);
printf(“Read %d bytes: %s/n”, data_processed, buffer);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
父进程和子进程 P535
把pipes当做标准输入输出 //P537
你已经知道怎样去读取一个空的pipe,已经比较清楚的了解到用a pipe 去连接两个进程。你可以安排一个pipe的文件描述符去指定一个已知的值,通常是标准输入流0或者标准输出流1。这样有一个好处,你可以调用一个不希望是文件描述符作为参数的标准程序。你需要用到下面两个函数。
#include <unistd.h>
int dup(int file_descriptor);
int dup2(int file_descriptor_one, int file_descriptor_two);
dup函数的目的是去打开一个新的文件描述符,有点像open函数。 不同点是dup创建的信文件描述符和已经存在的文件描述符关联到同一个文件。在使用dup后,产生的新的文件描述符总是最小的变量,dup2也一样。
dup怎么帮助进程传递数据?标准的输入流文件描述符总是0,dup则总是返回一个新的最小变量值文件描述符。当第一次关闭文件描述符0然后调用dup,这个新的文件描述符将是0。因为这个新的描述符是一个已经存在的描述符的复制品,标准输入会转向去访问一个文件或pipe。你可以创建两个文件描述符关联到同一个文件或者pipe.并且其中一个是标准输入。
Named Pipes: FIFOs // P540