3

下面的代码片段只会等待用户Enter第一次点击;之后,它会循环浏览所有其余.pcap文件,而无需等待用户输入。

$| = 1;

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

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

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

4

2 回答 2

2

你关心tcpreplay输出吗?重定向 stdout 和 stderr 似乎可以解决这个问题:

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

或者,您可以使用它来捕获tcpreplay输出:

my $tcpreplay_output = `tcpreplay -i eth0 -M 20 $_ 2>&1`;
于 2016-04-03T14:43:25.470 回答
2

tcpreplay将 STDIN 设置为使用非阻塞 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 错误:./replay 第 10 行 <STDIN> 第 1 行的资源暂时不可用。

这对应于 errno EAGAINread如果标记为非阻塞的文件描述符必须阻塞以等待 I/O,则返回。


如果您的系统实现fcntl了,您可以通过在每次调用后将 STDIN 设置为使用阻塞 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应该修复。

于 2016-04-06T00:27:19.033 回答