次のスニペットは、ユーザーがEnter最初にヒットするまで待機します。その後、.pcap
ユーザーの入力を待たずに、残りのすべてのファイルを循環します。
$| = 1;
while (<*.pcap>) {
print "$_";
<STDIN>;
system("tcpreplay -i eth0 -M 20 $_");
}
これがループの繰り返しごとにユーザー入力を待たないのはなぜですか?
tcpreplay
非ブロッキング I/O を使用するように STDIN を設定します。これにより、データが利用できない場合、読み取りですぐにエラーが返されます。これは、次の戻り値を確認することで確認できます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 でリソースが一時的に利用できません。
これは、非ブロッキングとしてマークされたファイル記述子が I/O を待機するためにブロックする必要がある場合に返される errnoEAGAIN
に対応します。read
システムが を実装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
修正する必要があります。
tcpreplay
アウトプットを気にしますか?stdout と stderr をリダイレクトすると、この問題が解決するようです。
system("tcpreplay -i eth0 -M 20 $_ >/dev/null 2>&1");
tcpreplay
または、これを使用して出力をキャプチャできます。
my $tcpreplay_output = `tcpreplay -i eth0 -M 20 $_ 2>&1`;