无需将$ SIG {CHLD}设置为IGNORE或自定义信号处理程序即可收获子项

Mic*_*ael 7 perl parent-child signal-handling

我正在尝试编写一个为每个连接分叉的套接字服务器.除了一个小警告之外我一直很成功:我的子进程使用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;
}
Run Code Online (Sandbox Code Playgroud)

如果我使用上面显示的代码,一切正常,但我最终得到了一堆僵尸进程.如果我加

local $SIG{CHLD} = 'IGNORE';
Run Code Online (Sandbox Code Playgroud)

僵尸被收获,但Net :: OpenSSH-> capture2()方法调用有一个混乱的返回代码.我假设我的信号处理程序干扰了Net :: OpenSSH需要正常工作的一些自定义处理程序?

mob*_*mob 11

继续在父进程中设置SIGCHLD处理程序,但在子进程中禁用它 - 例如local $SIG{CHLD}fork调用之后立即放置.

在子进程中,SIGCHLD事件来自Net::OpenSSH方法,Net::OpenSSH模块将处理这些事件.

在父进程中,SIGCHLD事件来自您的子进程退出.这些正是您感兴趣的事件以及您需要处理以防止僵尸的事件.


Chr*_*sen 8

如果您永远不需要忽略子项并在同一进程中使用Net :: OpenSSH,那么您可以$SIG{CHLD} = 'IGNORE'在不使用Net :: OpenSSH的进程中使用(例如,分离"自动获取"子进程的单个服务器进程) )并将其重置为$SIG{CHLD} = 'DEFAULT'使用Net :: OpenSSH的进程(例如服务器的子进程).


或者,您可以waitpid在每个新客户端连接之后在循环中使用非阻塞.你仍然可以在一个或多个僵尸身边闲逛,但是它们都会在下一次连接时被收获.如果你切换到使用select(或类似IO :: Select之类的东西),你可以通过在你的侦听套接字上做一个选择并在每次超时后进行一轮非阻塞僵尸收获来设置僵尸"生命周期"的上限返回以及每个"套接字就绪"返回.

waitpid部分perlfunc里:

如果你说

use POSIX ":sys_wait_h";
#...
do {
    $kid = waitpid(-1, WNOHANG);
} while $kid > 0;
Run Code Online (Sandbox Code Playgroud)

然后你可以做一个非阻塞等待所有挂起的僵尸进程.支持waitpid(2)或wait4(2)系统调用的计算机上可以使用非阻塞等待.