我想要一个Perl守护进程监听并接受来自客户端的传入连接,然后fork&执行另一个Perl程序来继续与客户端的对话.
只要分叉,我可以做到这一点 – 守护进程代码还包含子代码.但是我看不到打开的socket可以通过exec()传递给另一个Perl程序.
不知怎的,我得到这样的印象,这在Unix(这是我的环境)很容易,因此也在Perl中.实际上可以做到吗
解决方法
这可以通过三个步骤完成:
>清除文件描述符上的close-on-exec标志.
>告诉exec’d程序哪个文件描述符使用.
>将文件描述符还原到句柄.
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: $!";
现在文件描述符将保持打开,你需要告诉程序哪个描述符是:
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程序都遵循惯例.