C: 未检测到从 parent 到 child 进程的管道中的 EOF

C: Not detecting EOF in pipe from parent to child process

我正在学习 C 语言的编程课程,目前我们正在学习管道和进程。在 class activity 中分配了一个,我必须让 parent 创建一个 child 来打印从 parent 管道传输的输入。我可以让程序将输入通过管道传输到 child 并输出它,但是当我为 EOF 按 ctrl + D 时,我仍然可以输入(没有输出)。

我试着按照我的逻辑写在纸上,似乎是正确的,但有些地方不对。我试图硬编码一个我可以写的短语,这样我就可以退出我的child,但是当我试图补救这种情况时,我的管道坏了。

这是我的 2 个文件:

newshell.c

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

int main(void){
    pid_t child1;
    int fd[2];
    char buffer1[100];
    int bytes;

    pipe(fd);
    child1 = fork();

    if (child1 == 0){
        dup2(fd[0],fileno(stdin));
        close(fd[1]);
        printf("You are in the child.\n");
        execlp("./printdata","printdata.c",0);
    }
    else {
        dup2(fd[1],fileno(stdout));
        close(fd[0]);
        while(fgets(buffer1,sizeof(buffer1),stdin) != NULL){
            write(fd[1],buffer1,(strlen(buffer1)+1));
        }
        write(fd[1],"999",sizeof("999"));
        wait(0);
        close(fd[1]);
        close(fd[0]);

        printf("Child ended. You are in the parent.\n");
    }
    return 0;
}

printdata.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void){
    char buffer[100];
    int bytes;
    printf("You're in the new process\n");
    while(bytes = read(fileno(stdin),buffer,sizeof(buffer)) >= 0){
        printf("%s\n",buffer);
        if (strcmp(buffer,"999") == 0){
            return 0;
        }
    }
    printf("Done here\n");
    return 0;
}

这里的逻辑是,我在 parent 中创建了一个 child 进程,等待来自 parent 的输入。我硬编码了一个 'sentinel'(正如我的教授所说),因为当我输入它时没有检测到我的 EOF。老师接受了我的东西,因为大多数人都没有完成作业,但我想知道为什么它对我自己不起作用。

谢谢。

要点是:当您按下 CTRL+D 时,您会在 parent 的标准输入上发出 EOF 信号。 所以 parent 离开这个循环

while(fgets(buffer1,sizeof(buffer1),stdin) != NULL)

因为 fgets() returns NULL 在 EOF。

但是现在,您需要关闭 fd[1] fileno(stdout)(因为您复制了它并且在 [=30 之前都做了=] 调用 wait(0)),因为关闭引用该管道的最后一个文件描述符将在 child 进程的输入上发出 EOF 信号!我有点不清楚为什么你 dup2() fd[1]fileno(stdout),也许你应该把它去掉。

经过这些修改后,它应该可以正常工作。

parent 需要在调用等待之前关闭 fd[1]。只要任何进程打开管道的写入端,child 中的读取就会阻塞。在您的情况下,parent 保持写入端打开,等待 child 终止。并且 child 在等待 parent 关闭管道的写入端的读取时被阻塞。换句话说,写:

 close(fd[1]);
 wait(0);

并且,正如 ctx 指出的那样,您需要关闭 parent 中的标准输出,或者停止无意义的 dup2