こんにちは。こちらのカテゴリには初めての投稿です。よろしくお願いします。
C++を用いて、Fedora上で"tcp dump"コマンドを実行し、1秒ごとのeth0(NIC)を通過したackパケットを記録するプログラムを作成しています。(150秒分記録)
ソースコードは質問文最後に記載します。
質問は、下記のプログラムでtcpdumpから1行分実行結果を取り出す際に使用しているfgets関数についてです。
調べてみると、fgtes関数は失敗した際は、NULLを返し「停止」するとあります。
http://www.nxmnpg.com/ja/3/fgets
これがおそらく原因かと思いますが、何も通信が行われていない状況で実行すると、
temp = fgets(buf,150,pp);
の行でプログラムが止まってしまいます。(何かしら通信がある(パケットが通る)と再開します)
よって、正確な時間計測ができず、困っています。
私はC++を勉強したてで、あまり読みやすいプログラムではないと思います。申し訳ありません。
fgetsの代わりになるような関数、または方法はありませんでしょうか。
ご回答、よろしくお願い致します。
//num_ack[]に各秒におけるパケット数を記録します。
//教えてgooの仕様上、tabや半角スペースが使えないので行頭のスペースはすべて全角です。ご了承ください。
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string.h>
using namespace std;
#define N 150
int main()
{
time_t start,end;
int num_ack[N];
int i=0;
char buf[150];
char *src,*temp,*srcstr;
char cmp[150];
srcstr = "ack";//検索ワード:"ack"
FILE *pp;
pp = popen("tcpdump -i eth0","r");
//popen失敗検知
if(pp == NULL)
{
cout << "tcpdump failed" << endl;
exit(EXIT_FAILURE);
}
for(int k=0;k<N;k++) //num_ackを初期化
{
num_ack[k] = 0;
}
while(1)
{
start = time(NULL);
end = time(NULL);
while((int)(end - start) <1) //1秒間計測
{
temp = fgets(buf,150,pp); //tcpdumpから1行(1パケット分)をbufへ取得
src = strstr(buf,srcstr);//bufから、"ack"を検索
if(src != NULL && strcmp(buf,cmp) !=0) //検索結果がNULLでなく、前回から変更がある場合
{
num_ack[i] += 1;
strcpy(cmp,buf);
}
end = time(NULL);
}
j += 1;
}
pclose(pp);
return num_ack;
}
No.3ベストアンサー
- 回答日時:
>これがおそらく原因かと思いますが、何も通信が行われていない状況で実行すると、
>temp = fgets(buf,150,pp);
>の行でプログラムが止まってしまいます。(何かしら通信がある(パケットが通る)と再開します)
tcpdumpが何か出力するのを待ってる状態なので止まってるように見えるのは当然です。
例えば
#include <stdio.h>
int
main()
{
char buf[128];
if (fgets(buf, sizeof(buf), stdin) != NULL) {
printf("%s\n", buf);
}
return 0;
}
をコンパイルし実行するとどうなるかわかります?
popenとfgetsでやろうとするならsetbufでバッファリングをオフにしてselectを使って入力があるかどうかを調べるか、fcntlでノンブロッキングモードにしておくかじゃないかな
ご回答、ありがとうございます。
例に挙げられているソースをコンパイル、実行するとstdinがあるまで待ち、入ればそれを表示する動作のようです。
この例から、fgetsがtcpdumpが何か出力するのを待つ、という状況が把握できました。
fcntlを用いてノンブロッキングすることで問題は解決しました!
No.5
- 回答日時:
横道に完全にそれた感じもしつつ……。
http://www.nxmnpg.com/ja/3/fgets
> 読込みは、改行文字が見つかったり、ファイルの終了 あるいはエラーが見つかったりした場合に停止します。
の文の構造は,
「読込みは」(条件)「停止する」
ですね。つまり,停止するのは「読込み」です。
英語版では,
http://www.nxmnpg.com/3/fgets
> Reading stops when a newline character is found, at end-of-file or error.
と,Readingとstopsが並んでいて分かり易いのですが。
ご回答ありがとうございます。
文構造がうまく読めていなかったですね。。。
今回の件でfgetsの動作について少し理解できました!
ありがとうございました。
No.1
- 回答日時:
> while(1)
このループを抜ける条件は何ですか?ずっと回りっぱなしのように見えます。
>調べてみると、fgtes関数は失敗した際は、NULLを返し「停止」するとあります。
ということでしたら、
> temp = fgets(buf,150,pp); //tcpdumpから1行(1パケット分)をbufへ取得
tempがNULLかどうかを判定する必要はありませんか?
> if(src != NULL && strcmp(buf,cmp) !=0)
このif文を初めて通るときのcmpの値はどうなっていると思いますか?
> j += 1;
変数 j の定義が見当たりません。i が正しいですか?
この回答への補足
ご指摘・ご回答ありがとうございます。
whileの条件と、j += 1について訂正したものを、while文の中身のみ、再掲いたします。
fgetsが停止するというのは、仮にfgetsの結果がNULLだと、そこでプログラムの実行が止まってしまい、
NULLではなくなるまで、つまりパケットが流れ、tcpdumpから何か出力されるまで先に行かなくなるのです。
そうなると、下にあるend=time(NULL)を読み込まず、1秒を測れなくなってしまう状況です。
ちなみに、常に何かしらの通信を行わせている状態(fgetsがNULLとならない)では、問題なく1秒をカウントできます。
while(i<150)
{
start = time(NULL);
end = time(NULL);
while((int)(end - start) <1) //1秒間計測
{
temp = fgets(buf,150,pp); //tcpdumpから1行(1パケット分)をbufへ取得
src = strstr(buf,srcstr);//bufから、"ack"を検索
if(src != NULL && strcmp(buf,cmp) !=0) //検索結果がNULLでなく、前回から変更がある場合
{
num_ack[i] += 1;
strcpy(cmp,buf);
}
end = time(NULL);
}
i += 1;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
_TCHAR*での引数の読み込み
-
干支のプログラム
-
C言語、このコードを実行したい...
-
c言語でユーザ関数を利用して入...
-
int main()の・・・
-
3桁区切(コンマ)記号をつけ...
-
javaでunsignedは使えないので...
-
iconv_open失敗
-
std::stringstream で得るもの...
-
C言語 ミリ秒を日付に変換には
-
C言語のポインターで詰まっている
-
コンパイルエラー invalid ope...
-
'const char *' 型は 'char *' ...
-
【C++ TR1】tr1::tuple<T1, T2,...
-
ある商品のロス率を5%見込み、...
-
2÷3などの余りについて
-
信頼区間の1.96や1.65ってどこ...
-
Aの値からBの値を除するとは??
-
O(n log n)について2
-
マイナスからプラスへ転じた時...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringをwchar_tに変換したい
-
fgetsなどのときのstdinのバッ...
-
charからLPTSTRへの変換方法
-
C言語のfor文です。 繰り返しの...
-
文字列から空白を取り除きたい...
-
配列をnビットシフトする
-
間接操作のレベルとは
-
charでの計算?
-
テキストデータをそのままバイ...
-
型変換
-
'const char *' 型は 'char *' ...
-
double型の値をchar配列に変換...
-
間接参照のレベルが異なっています
-
干支のプログラム
-
atoi( ) の反対をやりたい
-
C言語です
-
絶対パスからのファイル名の切...
-
ネットワークにつながっている...
-
【C言語】文字型と整数型の違い
-
Win32APIでのエディットボック...
おすすめ情報