【发布时间】:2016-05-21 14:29:32
【问题描述】:
大多数开发人员都知道,进程定义了三个文件描述符,我们更常见的是stdin、stdout 和stderr。
据我所知,fd 分别静态定义为 0、1 和 2。这在 POSIX 标准中明确说明:http://pubs.opengroup.org/onlinepubs/009695399/functions/stdin.html
现在假设我有一组需要第四个的进程。例如,使用fork() exec() 创建的子进程需要在fork() 之前使用socketpair() 创建的控制套接字的句柄。对于此示例,第 4 个句柄(套接字)的目的是提供父进程和子进程之间的链接。现在问题来了……孩子怎么知道哪个FD是控制插座?只要我dup2(new_socket,CONTROL_SOCKET) 在fork() 和exec() 之间,我有什么理由不能为此使用静态数字(例如:#define CONTROL_SOCKET 3)。然后我就可以在孩子内部foo = write(CONTROL_SOCKET, bar, baz)。让我们认为任何其他 FDs 打开我的应用程序都应该在 exec 上关闭,所以我的逻辑是 dup2() 不会关闭任何不会被 exec() 关闭的东西。
我知道有几种可能的解决方法可以避免这样做(例如:将 FD 传递到环境变量或程序参数中),并且网络上有许多示例显示了如何这样做。我不明白的是正在解决什么问题?静态定义要避免的 FD 有什么问题?乍一看,感觉是在避免一个不存在的问题。某些系统是否使用 0、1 和 2 以外的 FD,我是否会在执行之前通过 dup2(<some fd>,3) 覆盖重要的内容?
注意: 这个问题实际上是一个关于编写可在现有 POSIX 操作系统之间移植的代码的问题。
【问题讨论】:
-
更好的方法是将 FD# 作为参数或环境变量传递,这样就不会出现这个问题。
-
我想我已经读过一些 shell 可能会打开其他描述符。但我认为应用程序不应该关心它们,所以如果你的代码覆盖它们也不是问题。
-
@Olaf Linux 内核并不关心这个奇怪的“C 标准”东西。你可以
close(0); close(1); close(2); execl(...);就好了。 -
@Olaf 也许我将其标记为“C”是不正确的。它根本不是一个真正的 C 问题,C 标准在这里也无济于事,因为 C 标准只列出了 C 语言 正常工作的要求。涵盖操作系统行为的标准不包含在 C 标准中。所以 Immubus 是正确的。虽然有诸如 POSIX 之类的 *nix 标准,但它们并没有完全涵盖常见的(便携式)行为。操作系统之间有很多实际上没有任何标准的约定。
-
@Olaf 实际上是在看 POSIX 标准,它是定义和标准的:pubs.opengroup.org/onlinepubs/009695399/functions/stdin.html 0,1 和 2 是 POSIX 系统上的固定值。
标签: c posix file-descriptor