【发布时间】:2023-09-19 22:35:01
【问题描述】:
我正在编写一个包含两个通过管道进行通信的进程的程序。子进程从父进程中读取一些参数,用它们执行一个shell脚本,并将结果逐行返回给父进程。
我的代码运行良好,直到我在父进程结束时编写了while(read()) 部分。孩子将执行 shell 脚本,从popen() 读取其回显并将它们打印到标准输出。
现在我也尝试将结果写入管道并在父端的while() 循环中读取它们,但它会阻塞并且子进程也不会将结果打印到标准输出。显然它在从父发送的管道中读取数据后甚至都达不到这一点。
如果我在父进程注释掉while(),子进程打印结果返回,程序顺利结束。
为什么即使我在父进程和子进程中都关闭了管道的写入端,while(read()) 也会阻塞?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
int read_from_file(char **directory, int *octal) {
FILE *file = fopen("input", "r");
if (file == NULL) {
perror("error opening file");
exit(1);
}
fscanf(file, "%s %d", *directory, octal);
}
int main(int argc, char *argv[]) {
char *directory = malloc(256);
int *octal = malloc(sizeof *octal);
pid_t pid;
int pfd[2];
char res[256];
if (pipe(pfd) < 0) {
perror("Error opening pipe");
return 1;
}
if ((pid = fork()) < 0)
perror("Error forking");
if (pid == 0) {
printf("client here\n");
if (read(pfd[0], directory, 256) < 0)
perror("error reading from pipe");
if (read(pfd[0], octal, sizeof(int)) < 0)
perror("error reading from pipe");
// This won't get printed:
printf("client just read from pipe\n");
// close(pfd[0]);
char command[256] = "./asd.sh ";
strcat(command, directory);
char octal_c[5];
sprintf(octal_c, " %d", *octal);
strcat(command, octal_c);
FILE *f = popen(command, "r");
while (fgets(res, 256, f) != NULL) {
printf("%s", res);
if (write(pfd[1], res, 256) < 0)
perror("Error writing res to pipe");
}
fclose(f);
close(pfd[1]);
close(pfd[0]);
fflush(stdout);
return 1;
}
read_from_file(&directory, octal);
if (write(pfd[1], directory, 256) < 0)
perror("Error writing dir to pipe");
if (write(pfd[1], octal, sizeof(int)) < 0)
perror("error writing octal to pipe");
int r;
close(pfd[1]);
while (r = read(pfd[0], res, 256)) {
if (r > 0) {
printf("%s", res);
}
}
close(pfd[0]);
while (wait(NULL) != -1 || errno != ECHILD);
}
【问题讨论】:
-
read在出错时返回 -1,因此您的while循环将永远不会终止。您需要检查这种情况。 -
这似乎不是问题的直接意义,但是“这不会被打印”的评论准确吗?这很容易与问题有关。
-
@JohnBollinger 我收到一条“客户端在这里”消息,它在那里阻塞,没有打印“客户端刚刚从管道读取”日志。我认为这一定与管道没有正确关闭有关,但我看不出我做错了什么,因为如果我在父进程中注释掉
while()(这样它就不会尝试从pipe),一切运行顺利并被打印出来,然后程序结束。 -
@Thomas 会不会是因为父进程试图读取它打印到管道的消息,而不是让子进程先读取它?