unix - 关闭子进程中打开的文件描述符

标签 unix fork parent-child file-descriptor setrlimit

有没有办法遍历已经打开的文件描述符(由父进程打开)并在子进程中一一关闭它们?

操作系统:Unix。

关闭原因:setrlimit() 的 RLIMIT_NOFILE 限制限制了一个进程可以分配的文件描述符的数量。如果我们想通过设置这个限制来限制我们的子进程,它取决于已经分配的文件描述符。

尝试在子进程中设置此限制是受到限制的,因为父进程有一些打开的文件描述符,因此我们不能将此限制设置为小于该数字。

示例:如果父进程分配了 10 个文件描述符,并且我们希望将子进程文件描述符数量限制为小于 10(比如 3),我们将需要关闭子进程内的 7 个文件描述符。

对此的解决方案可以使所有想要限制其子进程创建新文件或打开新网络连接的人受益。

最佳答案

以下习语并不少见(取自 MIMEDefang 的 C 部分):

/* Number of file descriptors to close when forking */
#define CLOSEFDS 256
...

static void
closefiles(void)
{
    int i;
    for (i=0; i<CLOSEFDS; i++) {
        (void) close(i);
   }
}

这是一种黑客行为(正如 MIMEDefang 代码自由承认的那样)。在许多情况下,从 FD 3(或 STDERR_FILENO+1)而不是 0 开始更有用。 close()返回 EBADF FD 无效,但这通常不会出现问题(至少在 C 中不会,在其他语言中可能会引发异常)。

由于您可以使用 getrlimit(RLIMIT_NOFILE,...) 确定文件描述符上限这是 defined作为:

RLIMIT_NOFILE

This is a number one greater than the maximum value that the system may assign to a newly-created descriptor. If this limit is exceeded, functions that allocate a file descriptor shall fail with errno set to [EMFILE]. This limit constrains the number of file descriptors that a process may allocate.



你可以使用这个(减去 1)作为循环的上限。
以上和ulimit -n , getconf OPEN_MAXsysconf(OPEN_MAX)应该都同意。

open()总是分配最低的空闲FD,打开文件的最大数量和最高的FD+1是相同的数字。

确定哪些文件是打开的,而不是 close()使用空操作 lseek(fd, 0, SEEK_CUR)这将返回 EBADF如果 fd 未打开(尽管为条件 lseek() 调用 close() 没有明显的好处)。 socatfilan循环 0 .. FD_SETSIZE调用 fstat()/fstat64() .

libslack daemon utility它守护任意进程也使用这种蛮力方法(同时确保在 inetd 下使用时保持前三个描述符打开)。

如果您的程序可以跟踪文件句柄,最好这样做,或使用 FD_CLOEXEC在可用的地方。但是,如果您希望进行防御性编码,您可能更愿意不信任您的父进程,例如由浏览器启动的外部处理程序/查看器进程,例如像这样long-lived and ancient Mozilla bug在 Unix 平台上。

对于偏执狂(您是否希望您的 PDF 查看器继承每个打开的 Firefox FD 包括您的缓存和打开的 TCP 连接?):
#!/bin/bash
# you might want to use the value of "ulimit -n" instead of picking 255
for ((fd=3; fd<=255; fd++)); do
  exec {fd}<&- # close
done
exec /usr/local/bin/xpdf "$@"

关于unix - 关闭子进程中打开的文件描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15266531/

相关文章:

c - 迷失在多个 Fork()、Pipe() 和 Select() 中

c - 为什么父 pid 返回的值与 getpid() 不同?

fork - unix 中的多个分支

C - 内部有 fork()/pipe() 的 WHILE 循环

vb.net - Windows 窗体 : Unable to Click to Focus a MaskedTextBox in a Non TopLevel Form

linux - unix - 文件的头部和尾部

linux - 可以安全地假设 sh 已安装吗?

linux - 从日期中获取月份和日期

linux - 根据分隔符将一个文件拆分为多个文件

php - 递归检查数据库中 child 的 parent