为什么我的Perl程序在fork之后不会收获子进程?

问题描述:

我一直在尝试使用Perl编写一个简单的ping扫描器供内部使用。由于它扫描24位CIDR网络,如果脚本运行在单个线程中,该脚本运行时间过长。我曾尝试添加fork功能来加速此过程,但由于在任何给定时间只有一个子进程处于活动状态,因此我的first attempt几乎同时发生。为什么我的Perl程序在fork之后不会收获子进程?

我的perlipc文件中以及在Perl Cookbook儿童进程读取并与第二版本出来了:

##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"; 

当我扫描我的内部网络输出为:

$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 

从结果中可以看出,执行成功扫描的线程打印“up”消息,干净地退出并由父进程收割。与此同时,其他的251个线程仍然挂在'/ sbin/init'上,这可以通过一个快速的'ps -ef'列表来看到。如果我在退出语句之前在子处理块中添加了'print'Child:$ currIP结尾\ n“',我的终端上剩余的251个进程的输出”在我的perl脚本退出后。

这是怎么回事?我认为与waitpid循环结合的$ SIG {CHLD}子例程将收获所有的子进程,并确保系统中不存在僵尸/悬挂进程。

同样我还希望能够在任何给定的时间运行特定数量的子进程,比如说,'n'个并发运行的子进程,只要有一个退出父进程就会启动另一个子进程但在任何特定时刻只有'n'个孩子。这可能吗?如果是,我可以得到一些伪代码来帮助指导我?

+0

为什么你的循环从1-254(253?)而不是0-255? – 2009-05-31 05:03:28

+0

Matt Boehm 255通常是广播地址(假设是/ 24子网)。 0也有特殊含义(在/ 24),但我忘记它是什么。 – 2009-05-31 05:59:08

它看起来像你的父母过程是在孩子面前完成的(因此从来没有机会收获)。试试这个:

#!/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; 
} 

当一个线程调用ping()时,它会一直尝试ping IP直到它设置响应。要解决这个问题,请尝试在ping()中包含超时作为第二个参数。它看起来像现在,剩下的线程继续ping响应,直到他们得到一个响应。

只要有一组N个线程,为什么不把0-255分成块,例如有两个线程,一个是从0-127变为128-255?为了简单起见,我将使用2的倍数作为线程数。

看看Parallel::ForkManager。它为您处理所有这些小细节。