9

Perlデーモンにクライアントからの着信接続をリッスンして受け入れさせ、別のPerlプログラムをフォークして実行し、クライアントとの会話を続けたいと考えています。

単純に fork するだけで、これは問題なく実行できます。この場合、デーモン コードには子のコードも含まれます。しかし、開いているソケットを exec() を介して別の Perl プログラムに「渡す」方法がわかりません。

どういうわけか、これは (私の環境である) Unix では簡単で、したがって Perl でも簡単だという印象を受けました。実際にできるのでしょうか?

4

1 に答える 1

15

これは、およそ 3 つの手順で実行できます。

  1. ファイル記述子のclose-on-execフラグをクリアします。
  2. exec されたプログラムに、使用するファイル記述子を伝えます。
  3. ファイル記述子をハンドルに復元します。

1. Perl (デフォルト) は、開くファイル記述子に close-on-exec フラグを設定します。これは、ファイル記述子がexec. 最初にこのフラグをクリアする必要があります:

use Fcntl;

my $flags = fcntl $fh, F_GETFD, 0 or die "fcntl F_GETFD: $!";
fcntl $fh, F_SETFD, $flags & ~FD_CLOEXEC or die "fcntl F_SETFD: $!";

2.これで、ファイル記述子は で開いたままになるのでexec、プログラムにそれがどの記述子であるかを伝える必要があります。

my $fd = fileno $fh;
exec 'that_program', $fd;  # pass it on the command line
# (you could also pass it via %ENV or whatever)

3.反対側のファイルハンドルを復元します。

my $fd = $ARGV[0];  # or however you passed it
open my $fh, '+<&=', $fd;  # fdopen
$fh->autoflush(1);  # because "normal" sockets have that enabled by default

これで、再び Perl レベルのハンドルができまし$fhた。

補遺:池上がコメントで述べたように、ソケットが3つの「標準」ファイル記述子(0(stdin)、1(stdout)、2(stderr))のいずれかを使用していることを確認することもできます。 2. 既知の番号を持っているので、何も渡す必要はありません。3. perl はそれらに対応するハンドルを自動的に作成します。

open STDIN, '+<&', $fh;  # now STDIN refers to the socket
exec 'that_program';

that_programを簡単に使用できるようになりましSTDINた。これは出力でも機能します。ファイル記述子 0、1、2 には、入力または出力専用であるという固有の制限はありません。これは、すべての UNIX プログラムが従う規則にすぎません。

于 2013-01-16T04:45:17.717 に答える