9

我想让 Perl 守护进程监听接受来自客户端的传入连接,然后fork & exec另一个 Perl 程序以继续与客户端的对话。

简单地分叉时我可以做到这一点 - 守护程序代码还包含子代码。但是我看不到打开的套接字如何通过 exec() “传递”到另一个 Perl 程序。

不知何故,我觉得这在 Unix(这是我的环境)中很容易,因此在 Perl 中也是如此。真的可以做到吗?

4

1 回答 1

15

这可以通过大约三个步骤完成:

  1. 清除文件描述符上的close-on-exec标志。
  2. 告诉执行程序使用哪个文件描述符。
  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

附录:正如 ikegami 在评论中提到的,您还可以确保套接字正在使用三个“标准”文件描述符之一(0(stdin)、1(stdout)、2(stderr)),它们是 1. 保持打开状态默认跨 execs,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 回答