【问题标题】:Can file descriptors other than the std in/out/err be defined statically?可以静态定义 std in/out/err 以外的文件描述符吗?
【发布时间】:2016-05-21 14:29:32
【问题描述】:

大多数开发人员都知道,进程定义了三个文件描述符,我们更常见的是stdinstdoutstderr

据我所知,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


【解决方案1】:

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

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

【讨论】:

  • 是的,我总是控制进程的启动方式...坦率地说,我根本不想 exec() 而是简单地分叉,但其他要求(包括需要使用 Pthreads)迫使我使用exec()清理进程。
【解决方案2】:

你不需要把它弄得那么复杂。

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

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

看到这个答案:https://stackoverflow.com/a/21596854/816536 但忽略“P1.c”的第二个变体——这是失败的方式。

【讨论】:

  • 我不是在建议“变通办法”。我建议更好的方法,使您的意图众所周知并且清晰简洁。做出假设总是比明确的更容易出错,无论它是否带来平台依赖性。准确和明确地表达自己的意图并不是真正的“额外工作”——而是一个非常好的学习习惯。你未来的自己会感谢你的!
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 2011-03-26
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    相关资源
    最近更新 更多