从管道读取作为标准输入时出现“坏的文件描述符”错误

5

我 fork 并设置了一个类似于这样的命令:

pid_t pid;
pid = fork();
if (pid == 0)
{   // I am the child
    freopen("/input_pipe","r",stdin);
    freopen("/output_pip","w",stdout);
    execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster
    // Should never get here
    perror("execl");
    exit(1);
}

在进程分叉之前,/input_pipe已经被创建并填充了数据。这在几乎所有情况下都可以正常工作。该命令从stdin中读取(使用read())并获取另一个进程写入管道的数据。但有时候该命令无法从stdin流中读取数据,并在尝试这样做时出现“坏文件描述符”错误。可能会导致这种错误的原因是什么?编辑:我已将freopen部分更改为以下内容:
    pipe_in = open(pipename_in, O_RDONLY);
    pipe_out = open(pipename_out, O_WRONLY);

    dup2(pipe_in, 0);
    dup2(pipe_out, 1);

尽管这个错误只出现得很少,但我会测试几天来确认。


你的“真实”代码是否通过将函数返回值与“NULL”进行比较来检查“freopen()”中的错误? - alk
1个回答

5
可能出现问题的一个原因是,“stdin”和“stdout”不一定与文件描述符0和1对应。在许多运行库的实现中,freopen函数可能会更改FILE*所属的文件描述符。文件描述符属于内核,而FILE*属于运行库,它们不一定是对齐的。
请参考这里:http://man7.org/linux/man-pages/man3/stdout.3.html “对其中一个流应用freopen(3)可以更改与该流相关联的文件描述符号码”
在execl之后,子进程只期望文件描述符0和1是标准输入和输出,但是可能发生freopen关闭了fd 0并连接另一个fd到(FILE*)stdin的情况。我建议您使用“open”,“close”,“dup”等系统调用直接处理文件描述符0和1(或者最好使用标准宏STDIN_FILENO和STDOUT_FILENO)。

嗯,你如何将 freopen 翻译成 open/close/dup 调用? - Robby75
不要翻译,你不需要修改标准流(即FILE *)stdin/stdout。文件描述符很重要。本文解释了如何做到这一点:https://dev59.com/12ox5IYBdhLWcg3wnllI - Giuseppe Guerrini
因此,我应该使用in_fd = open("/input_pipe", "r"); 和 dup2(in_fd, 0);而不是 freopen("/input_pipe","r",stdin); 对吗? - Robby75
这里是另一篇文章:http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/redirecting-standard-io.html(请参见“重定向POSIX文件描述符”段落) - Giuseppe Guerrini
我目前在测试时没有包括“close(in);”这部分 - 它似乎可以正常工作,为什么需要 close(in) 呢? - Robby75
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接