我在Windows上运行以下代码段。从客户端读取后,服务器开始连续监听。我希望在一段时间后终止此命令。
如果我在main.pl
中使用alarm()函数调用,那么它会终止整个Perl程序(此处为main.pl
),因此我将此system命令置于其中一个单独的Perl文件
并使用system命令在原始Perl文件中调用此Perl文件(alarm.pl
)。
但是通过这种方式,我无法在原始Perl文件中调用此system()
调用的输出,也无法在调用的一个Perl文件中调用。
有人可以让我知道终止system()
电话的方式,还是以我上面使用过的方式获取输出?
my @output = system("alarm.pl");
print"one iperf completed\n";
open FILE, ">display.txt" or die $!;
print FILE @output_1;
close FILE;
alarm 30;
my @output_1 = readpipe("adb shell cd /data/app; ./iperf -u -s -p 5001");
open FILE, ">display.txt" or die $!;
print FILE @output_1;
close FILE;
两种方式display.txt
始终为空。
答案 0 :(得分:15)
这里有一些单独的问题。
首先,为了防止alarm杀死你的脚本,你需要处理ALRM信号。请参阅alarm文档。你不应该需要两个脚本。
其次,system不捕获输出。如果你想这样做,你需要一个反引号变体或管道。 Stackoverflow已经有了答案。
第三,如果 alarm.pl 将任何内容放入 display.txt 中,则在重新打开时将其丢弃在 main.pl 中文件处于写入模式。您只需要在一个地方创建文件。当你摆脱额外的脚本时,你就不会遇到这个问题。
我最近遇到了alarm
和system
的一些问题,但是switching to IPC::System::Simple解决了这个问题。
祝你好运,:))
答案 1 :(得分:8)
我到底在想什么?您不需要此任务的后台进程。您只需按照perldoc -f alarm
函数中的示例操作,并将时间敏感的代码包装在eval
块中。
my $command = "adb shell cd /data/app; ./iperf -u -s -p 5001";
my @output;
eval {
local $SIG{ALRM} = sub { die "Timeout\n" };
alarm 30;
@output = `$command`;
alarm 0;
};
if ($@) {
warn "$command timed out.\n";
} else {
print "$command successful. Output was:\n", @output;
}
在eval
区块内,您可以常规方式捕获输出(使用反引号或qx()
或readpipe
)。虽然如果通话超时,也不会有任何输出。
如果您不需要输出(或者不介意一起黑客攻击某些进程间通信),那么几乎可以防止出现警报并在子进程中运行system
调用过程击>
$command = "adb shell cd /data/app; ./iperf -u -s -p 5001";
if (($pid = fork()) == 0) {
# child process
$SIG{ALRM} = sub { die "Timeout\n" }; # handling SIGALRM in child is optional
alarm 30;
my $c = system($command);
alarm 0;
exit $c >> 8; # if you want to capture the exit status
}
# parent
waitpid $pid, 0;
当孩子的警报响起并杀死孩子时,当孩子的waitpid
命令完成,或时, system
将返回。对于未处理的SIGALRM,$?
将保留系统调用的退出代码或其他内容(在我的系统上为142),如果SIGALRM处理程序调用{{1}},则保留255.
答案 2 :(得分:2)
我遇到了类似的问题,需要:
经过多次阅读Perl IPC和手动前叉和手册exec,我出来了这个解决方案。它被实现为模拟的“反引号”子例程。
use Error qw(:try);
$SIG{ALRM} = sub {
my $sig_name = shift;
die "Timeout by signal [$sig_name]\n";
};
# example
my $command = "vmstat 1 1000000";
my $output = backtick(
command => $command,
timeout => 60,
verbose => 0
);
sub backtick {
my %arg = (
command => undef,
timeout => 900,
verbose => 1,
@_,
);
my @output;
defined( my $pid = open( KID, "-|" ) )
or die "Can't fork: $!\n";
if ($pid) {
# parent
# print "parent: child pid [$pid]\n" if $arg{verbose};
try {
alarm( $arg{timeout} );
while (<KID>) {
chomp;
push @output, $_;
}
alarm(0);
}
catch Error with {
my $err = shift;
print $err->{-text} . "\n";
print "Killing child process [$pid] ...\n" if $arg{verbose};
kill -9, $pid;
print "Killed\n" if $arg{verbose};
alarm(0);
}
finally {};
}
else {
# child
# set the child process to be a group leader, so that
# kill -9 will kill it and all its descendents
setpgrp( 0, 0 );
# print "child: pid [$pid]\n" if $arg{verbose};
exec $arg{command};
exit;
}
wantarray ? @output : join( "\n", @output );
}
答案 3 :(得分:-2)
如果您的命令在您的系统上已经很常见,可以使用“timeout -n”来包装命令。