こんにちは。こちらのカテゴリには初めての投稿です。よろしくお願いします。
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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- Visual Basic(VBA) Excel-VBAでのファイルの開き方 4 2023/02/14 11:01
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringをwchar_tに変換したい
-
ネットワークにつながっている...
-
文字列から空白を取り除きたい...
-
配列をnビットシフトする
-
バイナリファイルをコピーする...
-
iconv_open失敗
-
100バイトのバイナリファイルを...
-
C言語 バイナリファイルをfloa...
-
C言語です
-
atoi( ) の反対をやりたい
-
VC++でコンパイルエラーが出ま...
-
2曲同時再生するにはどうした...
-
char型の扱える範囲とは?
-
'const char *' 型は 'char *' ...
-
main の引数には const 付けた方が
-
引数の渡し方と受け方(argv)
-
ひとつのプログラムにしたいの...
-
c#でbmp画像の上下反転
-
c言語の問題の説明、各所ごとに
-
_TCHAR*での引数の読み込み
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
【至急】C言語の問題です、どな...
-
charからLPTSTRへの変換方法
-
charでの計算?
-
配列をnビットシフトする
-
fgetsなどのときのstdinのバッ...
-
絶対パスからのファイル名の切...
-
文字列から空白を取り除きたい...
-
C言語のfor文です。 繰り返しの...
-
テキストデータをそのままバイ...
-
CStringをwchar_tに変換したい
-
switch文で文字を比較すること...
-
C言語の入力した文字を反転させ...
-
atoi( ) の反対をやりたい
-
double型の値をchar配列に変換...
-
C言語 ミリ秒を日付に変換には
-
'const char *' 型は 'char *' ...
-
文字列がNULLか空文字列かの判定
-
c++ 文字列を入力して、一文字...
-
型変換
-
干支のプログラム
おすすめ情報