2016-04-03 76 views
3

以下片段只会等待用户点击第一次输入;之后,它会循环浏览所有其余的.pcap文件,而无需等待用户输入。为什么使用tcpreplay的脚本不等待用户输入?

$| = 1; 

while (<*.pcap>) { 
    print "$_"; 
    <STDIN>; 

    system("tcpreplay -i eth0 -M 20 $_"); 
} 

为什么不等待每次循环迭代时的用户输入?

+0

这对我很好#perl -e'while(<*.txt>){print; <>}''为每次按Enter键打印一个文件名。你能在你的系统上测试它吗? – Borodin

+0

我测试过这个,它适用于一个简单的案例,但肯定会因'system'调用'tcpreplay'而中断。它只是跳过超过第一遍的任何内容,并且在将其分配给变量时,仅在第一遍时定义。 – stevieb

+0

谢谢你们。 “tcpreplay”有些奇怪。不知道是否有任何解决方法。 – packetie

回答

2

你关心tcpreplay输出吗?重定向输出和错误似乎解决这个问题:

system("tcpreplay -i eth0 -M 20 $_ >/dev/null 2>&1"); 

或者,你可以用它来捕捉tcpreplay输出:

my $tcpreplay_output = `tcpreplay -i eth0 -M 20 $_ 2>&1`; 
+1

感谢您的解决方法,它效果很好。不知道为什么原来的行为如此。 – packetie

1

tcpreplay sets STDIN to use non-blocking I/O,这会导致读取立即返回一个错误,如果没有数据可用。您可以通过检查的readline返回值看到:

use strict; 
use warnings 'all'; 
use 5.010; 

$| = 1; 

while (<*.pcap>) { 
    say; 
    die "readline error: $!" if ! defined <STDIN>; 

    system("tcpreplay -i eth0 $_") == 0 
     or die "tcpreplay failed: $?"; 
} 

第一次调用tcpreplay后,这与消息模具:

readline error: Resource temporarily unavailable at ./replay line 10, <STDIN> line 1.

这相当于给errno EAGAIN,这read的回报,如果一个标记为非阻塞的文件描述符将不得不阻塞以等待I/O。


如果你的系统实现fcntl,你可以通过设置标准输入每次调用后使用阻塞I/O,以tcpreplay解决这个问题:

use strict; 
use warnings 'all'; 
use 5.010; 

use Fcntl; 

$| = 1; 

while (<*.pcap>) { 
    say; 
    die "readline error: $!" if ! defined <STDIN>; 

    system("tcpreplay -i eth0 $_") == 0 
     or die "tcpreplay failed: $?"; 

    # Reset STDIN to use blocking I/O 
    my $flags = fcntl(STDIN, F_GETFL, 0) 
     or die "Couldn't get flags for STDIN: $!"; 
    fcntl(STDIN, F_SETFL, $flags & ~O_NONBLOCK) 
     or die "Couldn't set flags for STDIN: $!"; 
} 

这只是一种变通方法,虽然; tcpreplay应该是固定的。