Perl - 在fork / exec之间传递一个打开的套接字

时间:2013-01-16 04:00:26

标签: perl sockets exec fork

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

我可以在简单分叉时做到这一点 - 守护程序代码也包含子代码。但我不知道打开的插座是如何通过"跨越exec()到另一个Perl程序。

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

1 个答案:

答案 0 :(得分:14)

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

  1. 清除文件描述符上的 close-on-exec 标志。
  2. 告诉exec'd程序使用哪个文件描述符。
  3. 将文件描述符恢复为句柄。
  4. 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
    

    现在,您再次在$fh中拥有Perl级别的句柄。

    附录:正如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程序遵循的惯例。