2009-05-31 5 views
4

J'ai essayé d'écrire un scanner ping bare-bones en utilisant Perl pour un usage interne. Comme il analyse un réseau CIDR 24 bits, le script prend trop de temps à s'exécuter s'il s'exécute dans un seul thread. J'ai essayé d'ajouter une fonctionnalité de fork pour accélérer le processus, mais mon first attempt prenait à peu près le même temps car il n'y avait qu'un seul processus fils actif à la fois.Pourquoi mon programme Perl ne recueille-t-il pas les processus enfants après la fourchette?

Je lis sur les processus enfants dans le document perlipc et aussi dans le Perl Cookbook et est venu avec la deuxième version:

##Install the CHLD SIG handler 
$SIG{CHLD} = \&REAPER; 
sub REAPER { 
    my $childPID; 
    while (($childPID = waitpid(-1, WNOHANG)) > 0) { 
     print "$childPID exited\n"; 
    } 
    $SIG{CHLD} = \&REAPER; 
} 

my $kidpid; 
for (1 .. 254) { 
    my $currIP = join ".", (@ipSubset[0,1,2], $_); 

    die "Could not fork()\n" unless defined ($kidpid = fork); 
    if ($kidpid) { 
     #Parent process 
     #Does nothing 
    } 
    else { 
     #Child process 
     my $pingConn = Net::Ping->new(); #TCP 
     say "$currIP up" if $pingConn->ping($currIP); 
     $pingConn->close(); 

     #Nothing else to do 
     exit; 
    } 
} 

say "Finished scanning $ipRange/24"; 

Lorsque je scanne mon réseau interne la sortie est:

$perl pingrng2.pl 192.168.1.1 
192.168.1.2 up 
5380 exited 
192.168.1.102 up 
192.168.1.100 up 
5478 exited 
5480 exited 
Finished scanning 192.168.1.1/24 

Comme on peut le voir dans le résultat, les threads qui réussissent un scan impriment le message «up», sortent proprement et sont récoltés par le processus parent. Les 251 autres threads quant à eux sont laissés pendants attachés à '/ sbin/init' comme le montre une liste rapide 'ps -ef'. Si j'ajoute un 'print' Enfant: $ currIP se terminant \ n "'dans le bloc de traitement enfant juste avant l'instruction exit, j'obtiens la sortie des 251 processus restants sur mon terminal" après "que mon script perl soit terminé.

Que se passe-t-il ici? Je pensais que le sous-programme $ SIG {CHLD} couplé à la boucle waitpid récolterait tous les processus fils et garantirait qu'aucun processus zombies/dangling ne soit laissé dans le système. En même temps, j'aimerais aussi pouvoir exécuter un nombre spécifique de processus fils à un moment donné, par exemple, 'n' enfants qui s'exécutent simultanément, chaque fois que l'un quitte le processus parent commence un autre enfant si nécessaire mais n'a pas plus de 'n' enfants à un moment donné. Est-ce possible? Si oui, pourrais-je obtenir un pseudo-code pour m'aider?

+0

Quelle est la raison pour laquelle votre boucle passe de 1-254 (253?) Au lieu de 0-255? –

+0

Matt Boehm 255 est généralement l'adresse de diffusion (en supposant un sous-réseau/24). 0 a aussi une signification particulière (en a/24), mais j'oublie ce que c'est. –

+0

Matt, tous les 0 sont réservés pour l'ID réseau et tous les 1 pour l'adresse de diffusion. – aks

Répondre

6

Il semble que votre processus parent finisse avant les enfants (et n'a donc jamais l'occasion de les récolter). Essayez ceci:

#!/usr/bin/perl 

use 5.010; 
use strict; 
use warnings; 

use Net::Ping; 

my @ipSubset = (192, 168, 10); 

my $i = 0; 
my @pids; 
for my $octet (1 .. 254) { 
    my $currIP = join ".", @ipSubset[0 .. 2], $octet; 

    die "Could not fork()\n" unless defined (my $pid = fork); 

    #parent saves chlidren's pids and loops again 
    if ($pid) { 
     push @pids, $pid; 
     next; 
    } 

    #child process 
    my $pingConn = Net::Ping->new; 
    say "$currIP up" if $pingConn->ping($currIP); 
    $pingConn->close(); 
    exit; 
} 

#wait on the children 
for my $pid (@pids) { 
    waitpid $pid, 0; 
} 
+0

J'ai essayé de le paramétrer sur 'IGNORE' mais la plupart des threads sont toujours laissés pendants comme expliqué ci-dessus. – aks

+0

J'ai regardé partout pour un moyen facile de le faire ... ce petit pour boucle à la fin était tout ce dont j'avais besoin ... merci beaucoup – bcasp

3

Lorsqu'un thread ping() appelle continue d'essayer de ping sur l'IP jusqu'à ce qu'il fixe une réponse. Pour résoudre ce problème, essayez d'inclure un délai d'attente en tant que second argument dans ping(). Il semble que pour le moment, les threads restants continuent à envoyer une requête ping jusqu'à ce qu'ils en aient une.

En ce qui concerne le nombre N de threads, pourquoi ne pas diviser le 0-255 en morceaux, par exemple avec deux threads, un qui va de 0-127 et un qui va de 128-255? Je voudrais utiliser un multiple de 2 pour votre nombre de threads par souci de simplicité.

Questions connexes