C: 将标准输入、标准输出重定向到管道
C: redirecting stdin, stdout to pipes
我正在正确理解管道和 FD,我正在尝试编写以下程序:
该程序基本上像 gzip 一样使用选项 -cf 压缩内容。
基本思路是:
我在 parent 进程中创建了两个管道,然后我 fork 了两次,这样我就有了两个 children。在第一个 child 中,我将第一个管道的读取端重定向到标准输入,将第二个管道的写入端重定向到标准输出。然后我使用 -cf 选项执行 gzip,以便它写入 stdout(现在是 pipe2 的写入端)
在第二个child中,我从pipe2读取并直接输出或保存到文件。
然而,问题是没有数据到达第二个 child 并且我不确定为什么。这是代码:
int main(int argc, char **argv) {
char *file;
int out = 0;
if(argc == 2) {
file = argv[1];
out = 1;
} else if (argc > 2) {
exit(EXIT_FAILURE);
}
int c1pipe[2];
int c2pipe[2];
pipe(c1pipe);
pipe(c2pipe);
int f;
for(int i = 0; i < 2; i++) {
switch(f = fork()) {
case 0: //child
if(i == 0) { //first loop iteration, child 1
close(c1pipe[1]);
dup2(c1pipe[0], fileno(stdin));
close(c1pipe[0]);
close(c2pipe[0]);
dup2(c2pipe[1], fileno(stdout));
close(c2pipe[1]);
execlp("gzip", "gzip", "-cf", (char *) NULL);
} else if (i == 1) { //second loop iteration, child2
close(c1pipe[0]);
close(c1pipe[1]);
close(c2pipe[1]);
FILE *read = fdopen(c2pipe[0], "r");
char buffer[1024];
if(out == 0) { //output to stdout
while(fgets(buffer, 1024, read) != NULL) {
fprintf(stdout, "%s", buffer);
fflush(stdout);
}
} else { //write to specified file
FILE *writeto = fopen(file, "w");
while(fread(buffer, sizeof(char), strlen(buffer)+1, read) > 0) {
fwrite(buffer, sizeof(char), strlen(buffer)+1, writeto);
fflush(writeto);
}
fclose(writeto);
}
close(c2pipe[0]);
fclose(read);
}
break;
case -1: //err
//not implemented
break;
default: //parent
if(i == 0) {
close(c2pipe[0]);
close(c2pipe[1]);
close(c1pipe[0]);
FILE *writer;
writer = fdopen(c1pipe[1], "w");
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin) != NULL) {
fwrite(buffer, sizeof (char), strlen(buffer)+1, writer);
}
close(c1pipe[1]);
fclose(writer);
}
break;
}
}
return 0;
}
请原谅遗漏的错误处理,因为我想创建一个 quick-and-dirty 版本。
感谢任何帮助。
在 parent 进程中,您在分叉第二个 child 之前关闭了 c2pipe 的两端。
如果您对任何 read/write 调用进行了错误处理,您可能已经明白了这一点。事实上,如果您检查 dup2 调用是否有错误,然后查看 errno,您可能会发现它是 EBADF
(错误的文件描述符)。
另一个问题是您的 parent 进程在知道两个 child 进程都已完成之前就退出了。这意味着 child 进程将收到信号并自行终止。 parent 需要调用 wait()
的变体之一,以确保 children 都已消失。
我正在正确理解管道和 FD,我正在尝试编写以下程序: 该程序基本上像 gzip 一样使用选项 -cf 压缩内容。 基本思路是:
我在 parent 进程中创建了两个管道,然后我 fork 了两次,这样我就有了两个 children。在第一个 child 中,我将第一个管道的读取端重定向到标准输入,将第二个管道的写入端重定向到标准输出。然后我使用 -cf 选项执行 gzip,以便它写入 stdout(现在是 pipe2 的写入端)
在第二个child中,我从pipe2读取并直接输出或保存到文件。 然而,问题是没有数据到达第二个 child 并且我不确定为什么。这是代码:
int main(int argc, char **argv) {
char *file;
int out = 0;
if(argc == 2) {
file = argv[1];
out = 1;
} else if (argc > 2) {
exit(EXIT_FAILURE);
}
int c1pipe[2];
int c2pipe[2];
pipe(c1pipe);
pipe(c2pipe);
int f;
for(int i = 0; i < 2; i++) {
switch(f = fork()) {
case 0: //child
if(i == 0) { //first loop iteration, child 1
close(c1pipe[1]);
dup2(c1pipe[0], fileno(stdin));
close(c1pipe[0]);
close(c2pipe[0]);
dup2(c2pipe[1], fileno(stdout));
close(c2pipe[1]);
execlp("gzip", "gzip", "-cf", (char *) NULL);
} else if (i == 1) { //second loop iteration, child2
close(c1pipe[0]);
close(c1pipe[1]);
close(c2pipe[1]);
FILE *read = fdopen(c2pipe[0], "r");
char buffer[1024];
if(out == 0) { //output to stdout
while(fgets(buffer, 1024, read) != NULL) {
fprintf(stdout, "%s", buffer);
fflush(stdout);
}
} else { //write to specified file
FILE *writeto = fopen(file, "w");
while(fread(buffer, sizeof(char), strlen(buffer)+1, read) > 0) {
fwrite(buffer, sizeof(char), strlen(buffer)+1, writeto);
fflush(writeto);
}
fclose(writeto);
}
close(c2pipe[0]);
fclose(read);
}
break;
case -1: //err
//not implemented
break;
default: //parent
if(i == 0) {
close(c2pipe[0]);
close(c2pipe[1]);
close(c1pipe[0]);
FILE *writer;
writer = fdopen(c1pipe[1], "w");
char buffer[1024];
while(fgets(buffer, sizeof buffer, stdin) != NULL) {
fwrite(buffer, sizeof (char), strlen(buffer)+1, writer);
}
close(c1pipe[1]);
fclose(writer);
}
break;
}
}
return 0;
}
请原谅遗漏的错误处理,因为我想创建一个 quick-and-dirty 版本。
感谢任何帮助。
在 parent 进程中,您在分叉第二个 child 之前关闭了 c2pipe 的两端。
如果您对任何 read/write 调用进行了错误处理,您可能已经明白了这一点。事实上,如果您检查 dup2 调用是否有错误,然后查看 errno,您可能会发现它是 EBADF
(错误的文件描述符)。
另一个问题是您的 parent 进程在知道两个 child 进程都已完成之前就退出了。这意味着 child 进程将收到信号并自行终止。 parent 需要调用 wait()
的变体之一,以确保 children 都已消失。