2010-08-12 8 views
7

Sto provando a scrivere un server socket che si biforca per ogni connessione. Ho avuto successo salvo un piccolo avvertimento: i miei processi figlio utilizzano Net: OpenSSH-> capture2() che richiede che $ SIG {CHLD} non sia impostato su IGNORE o su un gestore di segnale personalizzato. Come posso raccogliere i miei figli senza impostare il gestore del segnale o rallentare il processo genitore con wait o waitpid?

Ecco il mio codice del server:

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; 
} 

Se uso il codice come mostrato sopra, tutto funziona ma io alla fine con un po 'di processi di zombie. Se aggiungo

local $SIG{CHLD} = 'IGNORE'; 

gli zombie sono mietuto, ma il Net :: OpenSSH-> capture2() chiamata di metodo ha un codice di ritorno incasinato. Presumo che il mio gestore di segnale interferisca con un gestore personalizzato che Net :: OpenSSH deve funzionare correttamente?

risposta

11

Vai avanti e impostare un gestore di SIGCHLD nel processo padre, ma disattivare nelle processi figli - per esempio mettere un local $SIG{CHLD} subito dopo la chiamata fork.

Nei processi figlio, gli eventi SIGCHLD provengono dai metodi Net::OpenSSH e il modulo gestirà tali eventi.

Nel processo padre, gli eventi SIGCHLD provengono dai processi figli in uscita. Questi sono esattamente gli eventi a cui sei interessato e quelli che devi gestire per prevenire gli zombi.

8

Se non è necessario ignorare i bambini e utilizzare Net :: OpenSSH nello stesso processo, è possibile utilizzare $SIG{CHLD} = 'IGNORE' nei processi che non utilizzano Net :: OpenSSH (ad esempio, il processo a server singolo che si interrompe " "Mietuto automaticamente" bambini) e reimpostarlo su $SIG{CHLD} = 'DEFAULT' nei processi che utilizzano Net :: OpenSSH (ad esempio i figli del server).


In alternativa, è possibile utilizzare un non-blocking waitpid in un ciclo a dopo ogni nuova connessione client. Puoi ancora finire con uno o più zombi in giro, ma saranno tutti raccolti alla prossima connessione. Se passi ad usare select (o qualcosa come IO::Select), puoi impostare un limite superiore alla "durata" degli zombi eseguendo una selezione sul tuo socket di ascolto e facendo un giro di zombi non bloccanti che miete dopo ogni timeout di ritorno come così come ogni ritorno "pronto all'uso".

Dal waitpid section di perlfunc manpage:

Se dici

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

allora si può fare un'attesa non bloccante per tutti i processi zombie in sospeso. L'attesa non bloccante è disponibile su macchine che supportano le syscalls waitpid (2) o wait4 (2).

+1

+1 'waitpid' al di fuori di un gestore' SIGCHLD' è anche efficace per sbarazzarsi degli zombi – mob

Problemi correlati