質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

解決済

perlにてlastでwhileを抜け出したい。

TAKE147
TAKE147

総合スコア20

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

2回答

0リアクション

0クリップ

268閲覧

投稿2022/09/01 05:18

編集2022/09/02 05:45

前提

はじめて質問させていただきます。よろしくお願いします。
perl言語でtcpdumpの出力をファイルハンドルから読み込み、SYNフラグか、FINフラグに応じて処理をしていくプログラムを書いています。
その際while文とlastを使って、コマンド実行時に
./プログラム名 -n=10
のように指定した回数読み込みを行うのですが、lastが行われずにwhileを抜け出せません。

実現したいこと

-$nで指定した回数処理を行ったらすぐにwhile文を抜け出せるようにしたい

実行結果

出力は以下のようになります。 ---------------------------------- tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes Flag[S]! Flag[F]!! $count = 1 (中略) Flag[S]! Flag[F]!! $count = 10 $count=$n! -----------------------------------

特に知りたいこと

上記出力の最後、$count = 10の後に、lastが行われる条件 $count == $n が満たされていることを示す $count=$n!が表示されているにもかかわらず、lastによってwhile文を抜け出せていません。(もし抜け出していたらclose(PKT)とprint"finish!\n"が実行されているはず)どうして抜け出せないのかがわかりません。

該当のソースコード

perl

#!/usr/bin/perl -sw $count = 0; #ループ回数が指定されていないとき、10回とする unless ($n) { $n = 10; print "\$n=$n\n"; } # コマンドの出力をパイプでファイルハンドルへ渡す open (PKT, "tcpdump -l -i eth0 -tt -nn '((host 192.168.122.11) and (tcp) and (src port 80) and (tcp[tcpflags] & (tcp-syn|tcp-fin) != 0))'|"); # ファイルハンドルからtcpdumpの結果を読み込む while (<PKT>) { print "\n"; # フラグがSINのとき if(/^(\d+)\.(\d+).*> \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.(\d+).*(Flags \[S\.?\]).*seq (\d+)/) { print "Flag[S]!\n"; # フラグがFINのとき }elsif(/^(\d+)\.(\d+).*> \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.(\d+).*(Flags \[F\.?\]).*seq (\d+)/){ print "Flag[F]!!\n"; $count++; print "\$count = $count\n"; } if ($count == $n){ print "\$count=\$n!\n"; last; } } close (PKT); print"finish!\n";

試してみたこと

デバッグにてステップ実行を行いました。

($count=9までは省略) --------------------------------------------- main::(./trash.pl:16): print "\n"; DB<1> s main::(./trash.pl:19): if(/^(\d+)\.(\d+).*> \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.(\d+).*(Flags \[S\.?\]).*seq (\d+)/) { DB<1> s main::(./trash.pl:23): print "Flag[F]!!\n"; DB<1> s Flag[F]!! main::(./trash.pl:24): $count++; DB<1> s main::(./trash.pl:25): print "\$count = $count\n"; DB<1> s $count = 10 main::(./trash.pl:28): if ($count == $n){ DB<1> s main::(./trash.pl:29): print "\$count=\$n!\n"; DB<1> s $count=$n! main::(./trash.pl:30): last; DB<1> s main::(./trash.pl:34): close (PKT); DB<1> s s ----------------------------------------------- (ここで何も起きなくなるが、この状態の時にパケットを送ると) ----------------------------------------------- tcpdump: Unable to write output: Broken pipe main::(./trash.pl:39): print"finish!\n"; DB<1> finish!

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

otn

2022/09/02 02:04

実行しているのが、質問文のコードと違うとかですかね。
TAKE147

2022/09/02 02:10

回答ありがとうございます!確認したところソースコード、実行結果ともに掲載した通りです。
otn

2022/09/02 03:04 編集

> lastによってwhile文を抜け出せていません。 具体的な現象が書かれていませんが、$count のカウントアップが延々と続くと言うことですかね?
TAKE147

2022/09/02 03:15

いいえ、-n=10 で指定した回数より多くパケットを送る(FINフラグを受け取って$countが10より多くなる)とlastが実行されてプログラムは終了します。 ただ実現したいことは$countが10になったとき、つまり指定した回数処理を行ったらlastが行われて欲しいのです。説明が下手ですみませんが伝わりましたか?
KojiDoi

2022/09/02 04:32

デバッガのステップ実行でループ制御がどう働いているか見てみましたか?
TAKE147

2022/09/02 04:37

やり方すら知らないレベルでして、やっていないです。今から調べてやります!
TAKE147

2022/09/02 04:54

ステップ実行を行いました。こうして見るとlast自体は行われていて、ファイルハンドルのcloseも行われているけど最後のprint"finish!\n"が行われず、次のステップに進まない(デバッグでsを入力しても何も起こらない)みたいです。
KojiDoi

2022/09/02 04:57

print出力のバッファリングが効いているだけという可能性はありませんかね。
otn

2022/09/02 05:17

>FINフラグを受け取って$countが10より多くなる)とlastが実行されてプログラムは終了します。 と、 > ただ実現したいことは$countが10になったとき、つまり指定した回数処理を行ったらlastが行われて欲しいのです。=> 行われていないと言うことか? は矛盾しますが、どっちが正しいのでしょうか?頭の中を整理しましょう。 > print出力のバッファリングが効いているだけという可能性はありませんかね。 プログラムの末尾なのでそれは無いと思います。 > 確認したところソースコード、実行結果ともに掲載した通りです。 という回答なので。 まあ、確認が間違っていて、実はプログラムが違うという可能性もかなりあると思いますが。
TAKE147

2022/09/02 05:52

すみませんlastは行われていることがデバッグによりわかりました。ある意味当初の解決したい点は解決した(最初からしていた)と言えますが、私の実装したいことは$count=10になった直後、何も起こらなくなるのを防いですぐに print"finish!\n"が行われることです。
otn

2022/09/02 07:14 編集

実行結果欄にある、$count=$n! の表示の後、プログラムは終了するのですか?それともずっと実行中のままなのでしょうか?「whileから抜け出せてない」と思っていたと言うことは、実行中のままですかね。
otn

2022/09/02 07:13

実行は、具体的にどんな手段で行っていますか? 端末で起動しているシェルに対して、ファイル名を打ち込む?
TAKE147

2022/09/02 07:15

実行中のままです。その状態から新しいパケットを受け取ると、 tcpdump: Unable to write output: Broken pipe finish! となります。
TAKE147

2022/09/02 07:26

実行は仮想マシン(サーバ)の端末で行い、物理マシン(クライアント)からhttperfコマンドで仮想マシンのipアドレスに対して、コネクション数を例えば10のように指定して行っています。
TAKE147

2022/09/02 07:48

Ctrl+Cコマンドを送ることや、kill関数、exit関数を使うなどいくつか考えたのですが、実装できなかったり、finish!表示前に終了してしまったりと、うまくいかないみたいなので、この方法では難しいと判断しました。 そこでtcpdumpの-cオプションでパケットを受け取る回数を$nで指定して決まった回数tcpdumpを行う方法でやることにしました。 途中で打ち切るような形で申し訳ありませんが、これにて解決ということにさせていただきます。 アドバイスをくださった otn様、KojiDoi様ありがとうございました。
otn

2022/09/02 09:50

> 実行は仮想マシン(サーバ)の端末で行い、 具体的にはどのように行っているのですか?
TAKE147

2022/09/02 09:54

端末(コマンドプロンプトみたいなの)から ./プログラム名 -n=10 のようにして実行します。 実行したらtcpdumpが行われるので、クライアントからhttperfでパケットを送ります。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。