8

すでに開いているファイル記述子 (親プロセスによって開かれている) を繰り返し処理し、子プロセスでそれらを 1 つずつ閉じる方法はありますか?

OS: ユニックス。

終了の理由: setrlimit() の RLIMIT_NOFILE 制限により、プロセスが割り当てることができるファイル記述子の数が制限されます。この制限を設定して子プロセスを制限する場合は、既に割り当てられているファイル記述子に依存します。

親プロセスにはいくつかの開いているファイル記述子があるため、子プロセスでこの制限を設定しようとすることは制限されているため、この制限をその数より小さく設定することはできません。

例: 親プロセスに 10 個のファイル記述子が割り当てられており、子プロセスのファイル記述子の数を 10 未満に制限したい場合 (Say 3)、子プロセス内の 7 個のファイル記述子を閉じる必要があります。

これに対する解決策は、子プロセスが新しいファイルを作成したり、新しいネットワーク接続を開いたりすることを制限したいすべての人に役立ちます。

4

2 に答える 2

5

次のイディオムは珍しくありません (これは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-2.78 からのもので、後のリリースで実装がわずかに変更されています。)

これは一種のハックです (MIMEDefang コードが自由に認めているように)。多くの場合STDERR_FILENO+1、0 ではなく FD 3 (または )から開始する方が便利です。 は無効な FD をclose()返しますEBADFが、これは通常問題を引き起こしません (少なくとも C ではそうではなく、他の言語では例外がスローされる可能性があります)。

次のように定義さgetrlimit(RLIMIT_NOFILE,...)れているファイル記述子の上限を決定できるため:

RLIMIT_NOFILE

これは、システムが新しく作成された記述子に割り当てることができる最大値よりも 1 大きい数値です。この制限を超えると、ファイル記述子を割り当てる関数は失敗し、errno が [EMFILE] に設定されます。この制限により、プロセスが割り当てることができるファイル記述子の数が制限されます。

これを (1 を引いて) ループの上限として使用できます。上記とulimit -ngetconf OPEN_MAXおよびsysconf(OPEN_MAX)はすべて同意する必要があります。

は常に最小の空き FD を割り当てるためopen()、開いているファイルの最大数と最大の FD+1 は同じ数になります。

fdが開いていない場合に戻るclose()no-opを使用する代わりに、どのfdが開いているかを判断するには(ただし、条件付きを呼び出すことには明らかな利点はありません)。のループは 0 ..を呼び出して/を呼び出します。lseek(fd, 0, SEEK_CUR)EBADFlseek()close()socatfilanFD_SETSIZEfstat()fstat64()

任意のプロセスをデーモン化するlibslackdaemonユーティリティも、このブルート フォース アプローチを使用します (ただし、 で使用する場合は、最初の 3 つの記述子を開いたままにしておく必要がありますinetd)。

プログラムがファイル ハンドルを追跡できる場合は、追跡するか、可能な場合は使用することをお勧めしFD_CLOEXECます。ただし、防御的にコーディングしたい場合は、親プロセスを信頼しないことを好むかもしれません。たとえば、このUnix プラットフォームの長期にわたる古い Mozilla バグのように、ブラウザによって開始された外部ハンドラー/ビューアー プロセスなどです。

偏執狂の場合 (キャッシュを含むすべての開いている Firefox FD を PDF ビューアーに継承させ、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 "$@"

15 年後の更新この問題は、プロセスの作成が Netscape Portable Runtime (NSPR) API から LaunchApp を使用するように変更された Firefox 58 (2018) で解決されました。

于 2014-04-01T16:56:26.187 に答える
0

私の知る限り、Unix/POSIX で開いているファイル記述子を反復処理する一般的な方法はありません。説明している問題を処理する従来の方法は、必要に応じて配列やリストなどのデータ構造を使用して独自のコードでそれらを追跡し、後に子プロセスでそれらを閉じることfork()ですexec()

exec()ただし、一部のオペレーティング システムでは、子プロセスを作成した後に呼び出す場合に解決策が提供される可能性があります。を使用してファイル記述子のフラグを設定するFD_CLOEXECfcntl()か、オペレーティング システムのO_CLOEXECフラグを使用して、open()を呼び出す前にその特定のファイル記述子を閉じるように指示されますexec()。これらのフラグがサポートされているかどうか、およびどのフラグがサポートされているかを確認するには、ターゲット オペレーティング システムのドキュメントを参照する必要があります。

于 2013-03-07T10:44:11.530 に答える