【问题标题】:C: Not detecting EOF in pipe from parent to child processC:未检测到从父进程到子进程的管道中的 EOF
【发布时间】:2017-11-07 13:50:52
【问题描述】:

我正在学习一门专注于 C 语言的编程课程,目前我们正在学习管道和流程。分配了一个课堂活动,我必须让父母创建一个孩子来打印从父母管道传输的输入。我可以让程序通过管道将输入传递给孩子并输出它,但是当我 ctrl + D for EOF 时,我仍然可以输入输入(没有输出)。

我尝试在纸上遵循我的逻辑,这似乎是正确的,但有些地方是错误的。我试图硬编码一个我可以写的短语,以便我可以退出我的孩子,但是当我试图纠正这种情况时,我的管道坏了。

这是我的 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;
}

打印数据.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;
}

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

谢谢。

【问题讨论】:

  • pritnf("%s\n",buffer);?请发布可编译的代码。另请注意,read() 不会终止字符串。
  • 我修正了代码中的错字。
  • 请记住,使用 dup2 的一般模式是 dup2(f1, f2); close(f1);。也就是说,您几乎总是想立即关闭正在复制的描述符。
  • 哇哦。我混淆了 dup2 的逻辑。所以我的管道文件描述符的重点是允许进程之间的通信。所以当我 dup2(fd[x],in/out) 时,我基本上是在说我希望我的 in/out 指向管道的文件描述符?

标签: c unix process pipe broken-pipe


【解决方案1】:

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

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

因为 fgets() 在 EOF 上返回 NULL

但是现在,您需要关闭fd[1] fileno(stdout)(因为您在调用wait(0)之前调用wait(0)),因为关闭最后一个引用该管道的文件描述符将在输入到子进程时发出 EOF 信号!我有点不清楚为什么你 dup2() fd[1]fileno(stdout) 无论如何,也许你应该忽略它。

经过这些修改后,它应该可以按预期工作。

【讨论】:

  • 您的建议奏效了。谢谢你。我有一个关于我不必要的 dup2 的问题。我的理解是我必须将管道输出到标准输出,因为我正在从父母那里阅读,并希望将该输入输出给孩子。如果我删除那行代码,它为什么会起作用?
  • @totemc dup2() 将产生以下效果:如果您在父级中向标准输出写入内容,例如使用printf(),它将不会进入终端,而是进入您的管道和通过它到子进程。但既然你不这样做,它似乎没用,所以你可以简单地忽略它。
  • 我现在明白了。我曾认为我需要我的标准输出指向管道,以便它可以接收来自父级的输入。但如果是这样的话,我为什么需要我的write() 电话?我对两个进程之间的通信方式感到困惑。非常感谢。
【解决方案2】:

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

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

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

【讨论】:

  • 但是由于dup2(),现在有两个文件描述符引用管道的写入端,两个都必须关闭
  • 哎呀,到底为什么会发生这种情况!它没有任何作用。
  • 我以前有过这个,但会弄坏管道。我听从了 Ctx 的建议,得到了正确的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多