我想让 Perl 守护进程监听并接受来自客户端的传入连接,然后fork & exec另一个 Perl 程序以继续与客户端的对话。
简单地分叉时我可以做到这一点 - 守护程序代码还包含子代码。但是我看不到打开的套接字如何通过 exec() “传递”到另一个 Perl 程序。
不知何故,我觉得这在 Unix(这是我的环境)中很容易,因此在 Perl 中也是如此。真的可以做到吗?
这可以通过大约三个步骤完成:
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 程序都遵循的约定。