我正在尝试编写一个为每个连接分配的套接字服务器。除了一个小警告之外我一直很成功:我的子进程使用Net:OpenSSH-> capture2(),这要求$ SIG {CHLD}不能设置为IGNORE或自定义信号处理程序。如何在不设置信号处理程序的情况下收割我的孩子,或者使用wait或waitpid减慢父进程的速度?
这是我的服务器代码:
my $sock = new IO::Socket::INET (
LocalHost => 'localhost',
LocalPort => '1337',
Proto => 'tcp',
Listen => SOMAXCONN,
Reuse => 1,
);
die "Could not create socket: $!\n" unless $sock;
my $new_client, $pid;
while($new_client = $sock->accept()){
next if $pid = fork;
die "fork: $!" unless defined $pid;
close $sock;
while(<$new_client> ) {
#do Net::OpenSSH stuff
}
exit;
} continue {
close $new_client;
}
如果我使用上面显示的代码,一切正常,但我最终得到了一堆僵尸进程。如果我添加
local $SIG{CHLD} = 'IGNORE';
僵尸被收获,但Net :: OpenSSH-&gt; capture2()方法调用有一个混乱的返回代码。我假设我的信号处理程序干扰了Net :: OpenSSH需要正常工作的一些自定义处理程序?
答案 0 :(得分:11)
继续在父进程中设置SIGCHLD处理程序,但在子进程中禁用它 - 例如在local $SIG{CHLD}
调用之后立即放置fork
。
在子流程中,SIGCHLD事件来自Net::OpenSSH
方法,Net::OpenSSH
模块将处理这些事件。
在父进程中,SIGCHLD事件来自您的子进程退出。这些正是您感兴趣的事件以及您需要处理以防止僵尸的事件。
答案 1 :(得分:8)
如果您永远不需要忽略子项并在同一进程中使用Net :: OpenSSH,那么您可以在不使用Net :: OpenSSH的进程中使用$SIG{CHLD} = 'IGNORE'
(例如单个服务器进程在使用Net :: OpenSSH的进程(例如服务器的子进程)中将“自动获取”的子进程分离并重置为$SIG{CHLD} = 'DEFAULT'
。
或者,您可以在每个新客户端连接之后的循环中使用非阻塞waitpid
。你仍然可以在一个或多个僵尸身边闲逛,但是它们都会在下一次连接时被收获。如果您切换到使用select
(或类似IO::Select之类的东西),您可以通过在侦听套接字上执行选择并执行一轮非选择来设置僵尸“生命周期”的上限在每次超时返回后阻止僵尸收割以及每次“套接字就绪”返回。
来自waitpid
section的perlfunc manpage:
如果你说
use POSIX ":sys_wait_h"; #... do { $kid = waitpid(-1, WNOHANG); } while $kid > 0;
然后你可以对所有挂起的僵尸进程进行非阻塞等待。支持waitpid(2)或wait4(2)系统调用的计算机上可以使用非阻塞等待。