如何在Perl中获取由alarm()调用终止的命令输出?

时间:2010-04-02 16:37:22

标签: perl windows-services

案例1

如果我只在UL中运行命令,即iperf,那么我能够捕获txt文件中的输出

@output = readpipe("iperf.exe -u -c 127.0.0.1 -p 5001 -b 3600k -t 10 -i 1");
open FILE, ">Misplay_DL.txt" or die $!;
print FILE @output;
close FILE;

案例2

当我在DL模式下运行iperf时,我们知道服务器将开始监听。即使在从客户端获取数据后(如果我在局域网上使用服务器和客户端),如下所示的模式

@output = system("iperf.exe -u -s -p 5001 -i 1");

在服务器端:

D:\_IOT_SESSION_RELATED\SEEM_ELEMESNTS_AT_COMM_PORT_CONF\Tput_Related_Tools\AUTO
MATION_APP_\AUTOMATION_UTILITY>iperf.exe -u -s -p 5001
------------------------------------------------------------
Server listening on UDP port 5001
Receiving 1470 byte datagrams
UDP buffer size: 8.00 KByte (default)
------------------------------------------------------------
[1896] local 192.168.5.101 port 5001 connected with 192.168.5.101 port 4878
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[1896] 0.0- 2.0 sec 881 KBytes 3.58 Mbits/sec 0.000 ms 0/ 614 (0%)

没有出现命令提示符,进程是contd ...

在客户端:

D:\_IOT_SESSION_RELATED\SEEM_ELEMESNTS_AT_COMM_PORT_CONF\Tput_Related_Tools\AUTO
MATION_APP_\AUTOMATION_UTILITY>iperf.exe -u -c 192.168.5.101 -p 5001 -b 3600k -t
2 -i 1
------------------------------------------------------------
Client connecting to 192.168.5.101, UDP port 5001
Sending 1470 byte datagrams
UDP buffer size: 8.00 KByte (default)
------------------------------------------------------------
[1880] local 192.168.5.101 port 4878 connected with 192.168.5.101 port 5001
[ ID] Interval Transfer Bandwidth
[1880] 0.0- 1.0 sec 441 KBytes 3.61 Mbits/sec
[1880] 1.0- 2.0 sec 439 KBytes 3.60 Mbits/sec
[1880] 0.0- 2.0 sec 881 KBytes 3.58 Mbits/sec
[1880] Server Report:
[1880] 0.0- 2.0 sec 881 KBytes 3.58 Mbits/sec 0.000 ms 0/ 614 (0%)
[1880] Sent 614 datagrams

D:\_IOT_SESSION_RELATED\SEEM_ELEMESNTS_AT_COMM_PORT_CONF\Tput_Related_Tools\AUTO
MATION_APP_\AUTOMATION_UTILITY>

因此,服务器是cont。监听并永不终止,因此无法将服务器端输出到txt文件,因为它将转到下一个命令本身来创建一个txt文件。

所以我在从客户端收到所有数据后,采用了alarm()函数来终止服务器端(iperf.exe -u -s -p 5001)命令。

这是我的代码:

#! /usr/bin/perl -w
my $command = "iperf.exe -u -s -p 5001";
my @output;
eval {
    local $SIG{ALRM} = sub { die "Timeout\n" };
    alarm 20;
    #@output = `$command`;
#my @output = readpipe("iperf.exe -u -s -p 5001");
#my @output = exec("iperf.exe -u -s -p 5001");

my @output = system("iperf.exe -u -s -p 5001");
    alarm 0;
};
if ($@) {
    warn "$command timed out.\n";
} else {
    print "$command successful. Output was:\n", @output;
}
open FILE, ">display.txt" or die $!;
print FILE @output_1;
close FILE;

我知道使用系统命令我无法将o / p捕获到txt文件。我尝试了readpipe()exec()来电,但这些也是徒劳的。

有人可以看看,让我知道为什么iperf.exe -u -s -p 5001即使在闹钟调用后也没有终止并将输出转换为txt文件?


mobrule--最后我能够实现我想要的。下面是我使用的代码,但现在它也在每次后续运行中给我一个错误...

错误讯息:

The process cannot access the file because it is being used by another process.iperf.exe -u -s -p 5001 successful. Output was:

代码:

my @command_output;
eval { 
    my $file = "abc6.txt";    
    $command = "iperf.exe -u -s -p 5001";
    alarm 10;
    system("$command > $file");
    alarm 0;
close $file;
};
if ($@) {
    warn "$command timed out.\n";
} else {
   print "$command successful. Output was:\n", $file;
}
unlink $file;

输出:

abc6.txt
------------------------------------------------------------
Server listening on UDP port 5001
Receiving 1470 byte datagrams
UDP buffer size: 8.00 KByte (default)
------------------------------------------------------------
[1892] local 192.168.5.101 port 5001 connected with 192.168.5.101 port 3553
[ ID] Interval       Transfer     Bandwidth       Jitter   Lost/Total Datagrams
[1892]  0.0- 2.0 sec   881 KBytes  3.61 Mbits/sec  0.000 ms    0/  614 (0%)

此外,当每次运行此“iperf.exe”时,进程始终保持在Taskmanager中, 如果我在每次运行之前手动杀死它或者每次更改文件以获取输出,那么我就可以一个接一个地成功运行它。

您能否建议我如何杀死该进程(而不是从任务管理器手动执行)并解决该问题?

我尝试取消链接所使用的文件,但这并没有解决问题。

1 个答案:

答案 0 :(得分:1)

由于命令可能会超时,因此您需要在命令运行时保存尽可能多的输出。两种方法是:

  1. 在命令完成或超时后将输出保存到文件并读取文件内容:

    my @command_output;
    eval { 
        $SIG{ALRM} = { die "timeout\n" };
        alarm(30);
        system("$command > $file");
        alarm(0);
    };
    open my $fh, '<', $file;  # error handling omitted for brevity
    @command_output = <$fh>;
    close $fh;     # oops, this said "close $file" before ... not a big deal.
    
  2. open模式下使用-|运行命令,并在命令运行时保存尽可能多的输出:

    my @command_output = ();
    eval {
        $SIG{ALRM} = { ... };
        alarm(30);
        open my $process, "$command |"; # or open my $process, '-|', $command
        while (<$process>) {
            push @command_output, $_;
        }
        close $process;
        alarm(0);
    };
    

  3. 换一分钱,换一磅。

    在弄清楚iperf.exe是什么并下载之后,我让这个脚本“工作”了:

    use strict;
    use warnings;
    my $command = "C:/cygwin/usr/local/bin/iperf.exe -u -s -p 25005";
    my $file = "abc6.txt";
    my ($pid,@command_output);
    eval {
        my $process;
        $SIG{ALRM} = sub { 
          kill 'INT', $pid;
          close $process;
          die "timeout\n" 
        };
        alarm(10);
        $pid = open $process, "$command |";
        while (<$process>) {
          push @command_output, $_;
        }
        close $process;
        alarm(0);
    };
    print "eval block result was: $@\n";
    print "Output was:\n------\n",@command_output;
    

    我强烈建议您在尝试过多使用此代码之前先熟悉一下这些代码的所有函数和语法。