可以静态定义 std in/out/err 以外的文件描述符吗?

Can file descriptors other than the std in/out/err be defined statically?

正如大多数开发人员所知,进程定义了三个文件描述符,我们通常将其称为 stdinstdoutstderr

据我所知,fd 分别静态定义为 0、1 和 2。这在 POSIX 标准中有明确规定:http://pubs.opengroup.org/onlinepubs/009695399/functions/stdin.html

现在假设我有一组进程需要第 4 个。例如,使用 fork() exec() 创建的 child 进程需要在 fork() 之前使用 socketpair() 创建的控制套接字的句柄。对于这个例子,第 4 个句柄(套接字)的目的是在 parent 和 child 进程之间提供一个 link。那么问题来了……child是怎么知道哪个FD是control socket的呢?只要我在 fork()exec() 之间 dup2(new_socket,CONTROL_SOCKET),我就不能为此使用静态数字(例如:#define CONTROL_SOCKET 3)有什么原因吗?然后我就可以在 child 中 foo = write(CONTROL_SOCKET, bar, baz) 了。让我们把它当作阅读,任何其他 FDs 打开我的应用程序都应该在 exec 上关闭所以我的逻辑是 dup2() 不会关闭任何不会被 exec() 关闭的东西.

我知道有几种可能 work-arounds 可以避免这样做(例如:在环境变量或程序参数中传递 FD)并且网络上有许多示例展示了如何这样做.我不明白的是正在解决什么问题?静态定义要避免的 FD 有什么问题?乍一看,感觉是在回避一个不存在的问题。某些系统是否使用 0、1 和 2 以外的 FD,我可能会在 exec 之前用 dup2(<some fd>,3) 覆盖一些重要的东西吗?

注意: 这个问题实际上是关于编写可在 现有 POSIX 操作系统之间移植的代码的问题。

除了 0、1、2 之外,没有广泛使用文件描述符。我似乎记得一些跟踪系统使用超出该范围的固定文件描述符(虽然通常不是 3),但它们非常多例外(我不记得这个千年注意到它)。

总的来说,如果集合中的第一个进程能够确保描述符在启动时没有被使用,它就可以安全地将描述符传递给它的子进程。如果您发现该描述符已被使用,您可以打开一个不同的描述符到控制套接字,然后使用 fstat() 来比较这两个描述符。如果它们用于同一设备,您可以继续使用继承的描述符 3;如果没有,你需要dup2()close()控制插座。

如果您的进程计划自己简单地打开控制套接字,则无需特别担心使用哪个文件描述符。

您可能不想这样做的原因是,与 012 不同,您无法保证 3将打开,除非您始终控制流程的启动方式。

不过,为某些频道设置固定的描述符编号并没有错。 您绝对不会用 dup2(<some fd>, 3) 覆盖任何内容。 它只会掩盖 <some fd> 您的进程及其子进程,但 3 根本不会影响父进程。

你不需要搞得那么复杂。

即不要将 dup2() 与您不确定已关闭的目标描述符一起使用(例如,您知道是因为您刚刚关闭了它),或者您不想在这样做时隐式关闭。

只需按照评论中的建议,在命令行或环境变量中传递 new_socket 本身,作为表示其整数值的字符串。

查看此答案: 但忽略 "P1.c" 的第二个变体——这是失败的方式。