可以静态定义 std in/out/err 以外的文件描述符吗?
Can file descriptors other than the std in/out/err be defined statically?
正如大多数开发人员所知,进程定义了三个文件描述符,我们通常将其称为 stdin
、stdout
和 stderr
。
据我所知,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()
控制插座。
如果您的进程计划自己简单地打开控制套接字,则无需特别担心使用哪个文件描述符。
您可能不想这样做的原因是,与 0
、1
和 2
不同,您无法保证 3
将打开,除非您始终控制流程的启动方式。
不过,为某些频道设置固定的描述符编号并没有错。
您绝对不会用 dup2(<some fd>, 3)
覆盖任何内容。
它只会掩盖 <some fd>
您的进程及其子进程,但 3 根本不会影响父进程。
你不需要搞得那么复杂。
即不要将 dup2()
与您不确定已关闭的目标描述符一起使用(例如,您知道是因为您刚刚关闭了它),或者您不想在这样做时隐式关闭。
只需按照评论中的建议,在命令行或环境变量中传递 new_socket
本身,作为表示其整数值的字符串。
查看此答案: 但忽略 "P1.c" 的第二个变体——这是失败的方式。
正如大多数开发人员所知,进程定义了三个文件描述符,我们通常将其称为 stdin
、stdout
和 stderr
。
据我所知,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()
控制插座。
如果您的进程计划自己简单地打开控制套接字,则无需特别担心使用哪个文件描述符。
您可能不想这样做的原因是,与 0
、1
和 2
不同,您无法保证 3
将打开,除非您始终控制流程的启动方式。
不过,为某些频道设置固定的描述符编号并没有错。
您绝对不会用 dup2(<some fd>, 3)
覆盖任何内容。
它只会掩盖 <some fd>
您的进程及其子进程,但 3 根本不会影响父进程。
你不需要搞得那么复杂。
即不要将 dup2()
与您不确定已关闭的目标描述符一起使用(例如,您知道是因为您刚刚关闭了它),或者您不想在这样做时隐式关闭。
只需按照评论中的建议,在命令行或环境变量中传递 new_socket
本身,作为表示其整数值的字符串。
查看此答案: 但忽略 "P1.c" 的第二个变体——这是失败的方式。