Пожинайте детей, не устанавливая $SIG {CHLD} для ИГНОРИРОВАНИЯ или к пользовательскому обработчику сигналов

Я пытаюсь записать сервер сокета что ветвления для каждого соединения. Я был успешен за исключением одного маленького протеста: мои дочерние процессы используют 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 должен работать правильно?

7
задан Michael 12 August 2010 в 03:23
поделиться

2 ответа

Настройте обработчик SIGCHLD в родительском процессе, но отключите его в дочерних процессах - например, поместите local $ SIG {CHLD} сразу после вилки ] вызов.

В дочерних процессах события SIGCHLD поступают из методов Net :: OpenSSH , и модуль Net :: OpenSSH обрабатывает эти события.

В родительском процессе события SIGCHLD исходят от завершения дочерних процессов. Это как раз те события, которые вас интересуют, и те, которые вам нужно обработать, чтобы предотвратить зомби.

11
ответ дан 6 December 2019 в 09:57
поделиться

Если вам никогда не нужно игнорировать дочерние элементы и использовать 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).

8
ответ дан 6 December 2019 в 09:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: