I am trying to write a socket server that forks for every connection. I have been successful except for one small caveat: my child processes use Net:OpenSSH->capture2() which requires that $SIG{CHLD} not be set to IGNORE or to a custom signal handler. How can I reap my children without setting the signal handler or slowing down the parent process with wait or waitpid?
Here is my server code:
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;
}
If I use the code as shown above, everything works but I end up with a bunch of zombie processes. If I add
local $SIG{CHLD} = 'IGNORE';
the zombies are reaped, but the Net::OpenSSH->capture2() method call has a messed up return code. I’m presuming my signal handler is interfering with some custom handler that Net::OpenSSH needs to work properly?
Go ahead and set up a SIGCHLD handler in the parent process, but disable it in the child processes — for example put a
local $SIG{CHLD}immediately after theforkcall.In the child processes, SIGCHLD events come from the
Net::OpenSSHmethods, and theNet::OpenSSHmodule will handle those events.In the parent process, SIGCHLD events come from your child processes exiting. Those are exactly the events you are interested in and the ones you need to handle to prevent zombies.