我一直在尝试使用 Perl 编写一个简单的 ping 扫描仪供内部使用。由于它扫描 24 位 CIDR 网络,因此如果它在单个线程中运行,则该脚本需要很长时间才能运行。我曾尝试添加 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: $currIPending\n"',我会在我的 perl 脚本退出“之后”从终端上的剩余 251 个进程中获得输出。
这里发生了什么?我认为 $SIG{CHLD} 子例程与 waitpid 循环相结合将获得所有子进程并确保系统中没有僵尸/悬空进程。
同时,我还希望能够在任何给定时间运行特定数量的子进程,例如,'n' 个子进程同时运行,每当一个退出父进程时,如果需要,则启动另一个子进程但没有更多在任何特定时刻都比'n'个孩子。这可能吗?如果是,我可以得到一些伪代码来帮助指导我吗?