dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fd > 2)
close(fd);
根据UNIX环境中的"高级编程",上面的IF语句是必要的。这本书建议通过考虑FD = 1在一种情况下会发生什么,如果在另一种情况下会发生什么。
。如果Fd = 1,0(stdin)将关闭,然后将指向stdout,则1仍将指向stdout(因为dup2()如果该文件描述符等于第一个参数,并且将不会关闭文件描述符,并且将返回1)和2指向stdout。
如果fd = 3,每个文件描述符将首先关闭,然后指向任何文件3点。
如果大于2?
您不想打开任何未使用的文件描述符。将stdin
,stdout
和stderr
重定向到fd
之后,您不打算单独使用fd
- 它只是暂时打开的,以便您可以将所有标准描述符复制到其中。因此,您需要关闭它。
但是,如果它实际上与 stdin
, stdout
或 stderr
相同,则不想关闭它(这应该不太可能,但是如果其中一个已经在打开fd
之前已经关闭,则可能是可能的。因此,您需要if
来防止。
关于为什么关闭原始描述符很重要,某些类型的流才能在关闭所涉及的描述符的所有 all 时才做一些特别的事情(通常很重要)。例如,在所有描述符关闭之前,TCP连接将不会关闭,当删除所有链接并关闭所有描述符时,已删除的文件仅将其数据从磁盘中删除,并且管道的读取末端仅在eof时接收EOF所有参考写入端的描述符都关闭。因此,如果您将fd
打开,然后关闭标准描述符,它将阻止此最终动作发生。
您需要关闭描述符的一个非常普遍的情况是创建管道与儿童过程进行通信。代码通常看起来像:
pipe(fds);
switch (fork()) {
case 0: // child
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
execlp("program", "program", "arg1", (char*)NULL);
break;
case -1: // error
perror("fork");
exit(-1);
break;
default: // parent
close(fds[0]);
// Code that writes to fds[1]
}
孩子需要关闭管道的写入末端(fds[1]
),否则,当父母关闭时,孩子不会收到EOF。
dup2
调用的目的是将第一个文件描述符复制到第二个文件。因此,在拨打dup2
的三个调用后,文件描述符0、1和2是打开的,是文件描述符fd
的副本。随后致电close
然后关闭原始文件描述符。
如果您在调用close(fd)
之前没有检查fd > 2
,则您将关闭刚打开的文件描述符之一。例如,如果fd
为2,则close(fd)
与close(2)
相同。
打开后立即关闭文件描述符而不会对其进行任何操作。这就是需要检查的原因。
如果大于2,则点不是关闭fd
;相反,如果它是标准流之一,则不要关闭fd
。在您的示例中,关闭1
(Stdout)显然是不正确的。
但需要关闭附加的文件描述符。当可执行文件启动时,它有权相信只有FDS 0、1和2正在使用,因此在exec
ING之前清理 - 关闭FDS很重要。封闭式标志是另一个有用的选项。