Я пытаюсь записать сервер сокета что ветвления для каждого соединения. Я был успешен за исключением одного маленького протеста: мои дочерние процессы используют Net:OpenSSH-> capture2 (), который требует, чтобы $SIG {CHLD} не были установлены ПРОИГНОРИРОВАТЬ или к пользовательскому обработчику сигналов. Как я могу пожинать своих детей, не устанавливая обработчик сигналов или замедляя родительский процесс с ожиданием или 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';
зомби пожинают, но Сеть:: OpenSSH-> capture2 () вызов метода имеет испорченный код возврата. Я предполагаю, что мой обработчик сигналов вмешивается в некоторый пользовательский обработчик что Сеть:: OpenSSH должен работать правильно?
Настройте обработчик SIGCHLD в родительском процессе, но отключите его в дочерних процессах - например, поместите local $ SIG {CHLD}
сразу после вилки
] вызов.
В дочерних процессах события SIGCHLD поступают из методов Net :: OpenSSH
, и модуль Net :: OpenSSH
обрабатывает эти события.
В родительском процессе события SIGCHLD исходят от завершения дочерних процессов. Это как раз те события, которые вас интересуют, и те, которые вам нужно обработать, чтобы предотвратить зомби.
Если вам никогда не нужно игнорировать дочерние элементы и использовать Net :: OpenSSH в одном процессе, вы можете использовать $ SIG {CHLD} = 'IGNORE'
в процессы, которые не используют Net :: OpenSSH (например, процесс отдельного сервера, который разветвляет «автоматически извлеченные» дочерние элементы), и сбрасывают его на $ SIG {CHLD} = 'DEFAULT'
в процессах, которые используют Net :: OpenSSH (например, дочерние элементы сервера).
В качестве альтернативы вы можете использовать неблокирующий waitpid
в цикле после каждого нового клиентского соединения. Вы все еще можете остаться с одним или несколькими зомби, но все они будут пожнуты при следующем подключении. Если вы переключитесь на использование select
(или что-то вроде IO :: Select ), вы можете установить верхнюю границу «времени жизни» зомби, выполнив выбор на вашем слушающем сокете. и выполнение раунда неблокирующего зомби-жатвы после каждого возврата по таймауту, а также после каждого возврата «сокет готов».
Из раздела waitpid
man-страницы perlfunc :
Если вы говорите
, используйте POSIX ": sys_wait_h"; # ... делать { $ kid = waitpid (-1, WNOHANG); } пока $ kid> 0;
, то вы можете выполнить неблокирующее ожидание для всех ожидающих зомби-процессов. Неблокирующее ожидание доступно на машинах, поддерживающих системные вызовы waitpid (2) или wait4 (2).