c - 我应该使用什么方法来知道在进程 fork 然后执行后打开了哪些 fds

标签 c linux fork exec ipc

我知道 fork 和 exec 系列在执行后保留文件描述符。这种行为符合我的需要。同样来自 exec 手册:

The exec() family of functions replaces the current process image with a new process image.

所以,如果我做对了,在进程 forks 然后 execs 之后,程序需要额外的方法来了解哪些 fds 是打开的。

我寻求的是将要使用的 fds(加上需要关闭的 fds)传递给新进程的简单方法。

作为旁注。在 Windows 中,您只能看到进程正在使用的 fds 列表。不过,您需要降低级别才能做到这一点。

最佳答案

没有一个系统调用只是给你一个打开的文件描述符列表。但是您要解决的更大问题可以通过几种不同的方式解决。最典型的两种方式是:

如果子进程只处理一个客户端,那么只需让它从其标准输入 (fd 0) 读取并写入其标准输出 (fd 1);在 fork 之后但在执行之前,您使用 dup2 将适当的文件描述符重新分配给数字 0 和 1,单独保留 fd 2 (stderr),并关闭所有其他的(或者您使用 O_CLOEXEC/FD_CLOEXEC 提前,所以你不必这样做)。 一些 Unix 有一个叫做closefrom 的方便函数,它关闭所有数值大于或等于它的参数的文件描述符,但其他 Unix 拒绝采用它,原因如下我认为完全是假的。

如果 child 正在与包裹在一个文件描述符中的套接字或其他全双工通信 channel 交谈,您仍应将其分配为两者 fds 0 和 1,因为这样stdinstdout FILE 对象可以正常使用(直到你需要使用 recvfromshutdown,等等),并且因为如果 fds 0、1 和 2 中的任何一个未打开,许多库都会感到困惑。

此策略以最小的努力提供了良好的并行性,并允许子程序与 inetd 和类似的多路复用器一起使用。

如果 child 需要处理多个客户,不要将任何客户分配为 fds 0 或 1;而是将以逗号分隔的客户端套接字列表作为命令行参数进行处理。 child 应该只注意那些文件描述符,而忽略所有其他文件描述符,即使它们是打开的。 (你仍然应该尽最大努力在 fork 之后但在执行之前关闭所有不相关的 fds。)

为子进程中的多个客户端多路复用 I/O 需要更多的编程;如果您需要走这条路,我强烈建议您使用已经有人为您编写的异步 I/O 库,例如 libeventlibuv


在您确实需要知道哪些 fd 处于打开状态而您的 parent 没有给您任何线索的情况下,您有一个糟糕且不可移植的选项,以及一个糟糕但可移植的选项。

糟糕且不可移植的选项是打开并扫描目录 /proc/self/fd如果这个目录存在,它的条目对应于你进程中打开的文件描述符,它们的名字是十进制的描述符编号。这是一个糟糕的选择,因为您必须循环调用 readdir 并注意避免 fd 支持您正在使用的 DIR 句柄,并且它是不可移植的,因为,就我知道,只有 Linux 实现了这个特殊目录,即使在那里您也可能无法使用它。

可怕但可移植的选项是使用 getrlimit(RLIMIT_NOFILE) 查询最大文件描述符编号,然后从 0 循环到该编号调用 fcntl(i, F_GETFD),如果 fd 是打开的,它将返回一个非负数,如果它是关闭的,它将返回一个负数(并将 errno 设置为 EBADF)。这在任何地方都有效,但速度可能会非常慢,尤其是在最大文件描述符数量很大的情况下。

关于c - 我应该使用什么方法来知道在进程 fork 然后执行后打开了哪些 fds,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50682025/

相关文章:

linux - 在 zsh 中按模式拆分

c - 使用 fork 和 kill 信号

c - 在 Unix 中跟踪子进程

c - 在 log(n) 时间内移动数组中的元素

甚至在进入 main() 之前的代码段错误

无法计算出此 C 程序中使用函数计算总和和平均值的输出

叉()操作系统。 4 hi 进入输出,期待 3 hi

c - GCC 中没有参数检查

linux - 从三列文件中删除重复记录

linux - 如何为命令创建桌面快捷方式