首页 文章

(c / c)尝试从父进程强制EOF向子进程发送输入

提问于
浏览
4

我有一个非常简单的c / c程序,它要求子进程执行另一个程序,然后将一些数据发送到该子程序,并等待响应 .

子程序从stdin读取并在继续之前等待EOF .

我的问题是,子程序从管道写入接收初始输入,但它从未看到EOF(即使我关闭管道),所以它永远等待 .

我不确定为什么关闭管道并不意味着孩子的stdin的EOF?

这是代码:

http://gist.github.com/621210

3 回答

  • -1

    最常见的原因是您没有关闭管道的写入端,因此EOF永远不会被发送 . 常见的例子是当您的代码如下所示:

    int fds[2];
    pipe(fds);  // open a pipe
    if (fork()) {
        // parent process
        write(fds[1], ...  // write data
        close(fds[1]); // close it
    } else {
        // child process
        while (read(fds[0], ....) > 0) {
            // read until EOF
    

    这里的问题是管道的写端不会被关闭 - 父进程关闭它,但子进程仍然打开了写描述符 . 因此,孩子永远不会在读取描述符上看到EOF .

    在分配子项后,您需要做的第一件事是 close(fds[1]); ,关闭其写入描述符的副本 . 这样,当父级关闭对管道写入端的最后一个剩余引用时,子级将在读取端看到EOF .

    Edit

    看看你添加的链接,这正是问题 - 孩子仍然在其标准输出上打开管道的写端 . 不要将写入结束复制到子项中的stdout,只需将其关闭即可 . 在其他地方发送stdout(日志文件或/ dev / null)

    Edit

    对于双向沟通,你需要两个管道:

    int tochild[2], fromchild[2];
    pipe(tochild); pipe(fromchild);
    if (fork()) {
        close(tochild[0]);
        close(fromchild[1]);
        //write to tochild[1] and read from fromchild[0]
    } else {
        dup2(tochild[0], 0);
        dup2(fromchild[1], 1);
        close(tochild[0]); close(tochild[1]);
        close(fromchild[0]); close(fromchild[1]);
        exec(...
    }
    

    你需要非常小心地在父母中写入数据 - 但是如果要向孩子发送大量数据,你不能在读取孩子的输出之前发送所有数据,否则你可能会死锁(两个管道都填满了)当子块阻止尝试输出时,父块阻止尝试为子节点写入更多数据 . 您需要使用poll或select来判断何时有要读取的数据或要写入的空间,并且您可能希望将管道(父项至少结束)置于非阻塞模式 .

  • 3

    更新了我认为的问题:您正在阅读一个角色并检查该角色的EOF . 这不是read()系统调用的工作原理 . 在EOF时它将返回0 . 它不会将EOF写入缓冲区 .

    我也看到你一次只读一个角色 . 这是一种读取数据的糟糕方式 . 它比读取大缓冲区(比如4或8 kB)要快几倍 .

    我相信你在这里也有一个共同的错误 . 您没有检查write()的返回值 .

    写入系统调用不保证在返回之前写入所有数据 . 它可能会写入4000个字节并返回 . 它将返回写入的字节数 . 然后,您有责任更新缓冲区指针并再次调用write .

    或者它可能会返回错误代码,因此检查它是很重要的 .

  • 6

    这是我为你写的概念证明:

    Fork exec double pipe by dino ciuffetti

相关问题