为什么我的Perl程序在fork之后没有收到子进程?

时间:2009-05-31 04:07:50

标签: perl ipc fork zombie-process

我一直在尝试使用Perl编写一个简单的ping扫描程序供内部使用。由于它扫描24位CIDR网络,因此如果脚本在单个线程中运行,则运行时间太长。我已经尝试添加fork功能来加快这个过程,但我的first attempt几乎同时进行,因为在任何给定时间只有一个子进程处于活动状态。

我在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“'我在我的perl脚本退出之后从我的终端上的其余251个进程获得输出。

这里发生了什么?我认为$ SIG {CHLD}子程序与waitpid循环相结合将收获所有子进程并确保系统中没有留下僵尸/悬空进程。

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

3 个答案:

答案 0 :(得分:6)

看起来您的父进程正在孩子面前完成(因此永远不会有机会获得它们)。试试这个:

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

答案 1 :(得分:4)

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

答案 2 :(得分:3)

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

至于拥有N个线程数,为什么不将0-255分成块,例如有两个线程,一个是0-127,另一个是128-255?为简单起见,我会使用2的倍数作为你的线程数。