fgetsについて

このQ&Aのポイント
  • C++を用いて、Fedora上で1秒ごとのeth0(NIC)を通過したackパケットを記録するプログラムを作成中。
  • fgets関数についての質問。通信が行われていない状況で実行するとプログラムが止まってしまい、正確な時間計測ができない。
  • 代わりになる関数や方法を探している。C++初心者で、読みやすいプログラムではないと感じている。
回答を見る
  • ベストアンサー

fgetsについて

こんにちは。こちらのカテゴリには初めての投稿です。よろしくお願いします。 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; }

質問者が選んだベストアンサー

  • ベストアンサー
  • wormhole
  • ベストアンサー率28% (1619/5653)
回答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でノンブロッキングモードにしておくかじゃないかな

tomotomo2309jp
質問者

お礼

ご回答、ありがとうございます。 例に挙げられているソースをコンパイル、実行するとstdinがあるまで待ち、入ればそれを表示する動作のようです。 この例から、fgetsがtcpdumpが何か出力するのを待つ、という状況が把握できました。 fcntlを用いてノンブロッキングすることで問題は解決しました!

その他の回答 (4)

回答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が並んでいて分かり易いのですが。

tomotomo2309jp
質問者

お礼

ご回答ありがとうございます。 文構造がうまく読めていなかったですね。。。 今回の件でfgetsの動作について少し理解できました! ありがとうございました。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.4

#2へ 困ったことに http://www.nxmnpg.com/ja/3/fgets には本当に「停止する」と書いてあります・・

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

「fgtes関数は失敗した際は、NULLを返し「停止」するとあります」というのが何をどう読んだ結果の理解なのかさっぱりわからん.... 「停止」ってなんだ. wait系でがんばるのかなぁ. それでも本当に「1秒ごと」とはならないかもしれんけど.

tomotomo2309jp
質問者

お礼

ご回答ありがとうございます。 fgets関数の動作については質問文のURLの文からです。 No.5様ご指摘のように、停止するのは"読み込み"のようでした。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答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 が正しいですか?

tomotomo2309jp
質問者

補足

ご指摘・ご回答ありがとうございます。 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

  • fgets関数を使用したときの文字あふれについて

    fgets関数を用いて文字列を入力し、その長さを測るプログラムを作っています。 #include <stdio.h> #include <string.h> #define MAX 256 int main ( int, char *[] ); int main ( argc, argv ) int argc; char *argv[]; { char buf[( MAX )]; while ( 1 ){ memset ( buf, 0, sizeof( buf )); fgets ( buf, MAX, stdin ); if( fgets == NULL ){ break; } printf("入力した文字列の長さは%dです\n" ,strlen( buf )); } return 0; } このプログラムでは、256までしか文字列の長さを測ることができません。 もしこのプログラムで256を超える文字列を入力してしまうと、文字のあふれが発生し、 「入力した文字列の長さは256です」 「入力した文字列の長さは(あふれた文字列の長さ)です」 とこのようになってしまいます。 このプログラムで256以上の文字を読み捨てて、 「入力した文字列の長さは(あふれた文字列の長さ)です」 を表示しないようにできるのでしょうか? また読み捨てた文字列の長さを知ることはできるのでしょうか? もしかしたらfgets関数を使用すると不可能なのではないか?と思っています。 分かる方が居ましたらどうか教えて下さい。 よろしくお願いします。

  • fgetsの扱い方について

    今回、c++(言語はc言語)?で下のようなプログラムを書きました。 内容は、与えられたワイド文字列をマルチバイト文字列に変換した後、重要単語.txtに載っている単語が変換された文字列にあるか、を調べるものです。 ただ、実行できていないためプログラム自体があっているかわかりません。 これをvc++2010でエラーなくビルドしたあと、実行すると「ハンドルされていない例外が発生しました」とエラーが出ます。 使い方もよくわかってないブレークポイントを使って調べてみたところ、while(fgets(word,50,fp)!=NULL){ ここまで来るとエラーが発生してるみたいです。 なにが間違ってるんでしょうか? 解決策よろしくお願いします #include <stdio.h> #include <string.h> #include <locale.h> #include <stdlib.h> int main(){ setlocale( LC_ALL, "Japanese"); FILE *fp; fp=fopen("重要単語.txt", "w"); fclose(fp); if( (fp=fopen("重要単語.txt", "r")) ==NULL){ printf("File Not Open!!\n"); } wchar_t *input = L"音声認識を認識した後に変換を行う"; char str[200]; char word[50]; char iword[100]="●"; int pt=0,pp=0,cnt=0,i=0; //str=input;wchar_t→char変換する size_t wlen=0; wcstombs_s(&wlen,str,500,input,_TRUNCATE); while(fgets(word,50,fp)!=NULL){ strcat(word,'\0'); while(str[pt]!='\0'){ if(word[pp]=='\0'){ pp=0; strcat(iword,word); strcat(iword,"\n"); } else if(str[pt]==word[pp]){ pt++; pp++; } else{ pt=pt-pp+1; pp=0; } } pt=0; } fclose(fp); printf("変換後→%s\n",str); printf("重要単語\n%s",iword); return 0; } 重要単語.txtの中身 認識 音声 変換

  • fgetsとsscanfの使い方

    初歩的な質問で申し訳ないのですが、fgetsとsscanfの使い方が合っているか確認願います fgets(char *s , int n ,FILE *fp); -> fpから1行(nで指定した文字数)読み込み、sに格納する sscanf(char buf, "%s", char string); -> bufから%sを読み込み、stringに格納する まだ使い慣れていないのでどっちから読み込むのかこんがらがってます 上記の解釈でよろしいのでしょうか?

  • fgetsで2行目から文字化け

    fgetsでファイルを一行ずつ読み込みたいのですが、二行目以降が文字化けしてしまいます。 ******* ソース ******* #include <windows.h> #include <stdio.h> FILE *fp; if ((fp = fopen("textlist.txt", "r")) == NULL){ MessageBox(NULL, TEXT("ファイルを開けません"), NULL, NULL); exit (1); } while (1) { TCHAR buf[128] = {0}; if (fgets(buf, sizeof(buf), fp) == NULL) break; MessageBox(NULL,buf,NULL,NULL); } fclose(fp); ***** textlist.txt ***** あいうえお かきくけこ さしすせそ メッセージボックスの一回目は正しく"あいうえお"と表示されますが、二回目・三回目は文字化けしています。 最終的に一行ずつ分けて配列に入れたいので、fgetsで出来たらと思っています。 よろしくお願いします。

  • C言語におけるfgetsを用いたループ処理について

    C言語において、文章を読み込むためにfgetsを用いて下記のプログラムを書いたのですが、*において入力を受け付けなくなります。 これを解消する方法はないでしょうか? ちなみにコンパイラはBBC、開発環境はVistaです。 なお、簡略のため#include,main等は省略しています。 //以下プログラム #define SIZE 16384 char moji[SIZE] = {""}; char buf[SIZE]; //EOF(^Z)になるまで、文字列を受け取る while(fgets(buf, sizeof(buf), stdin) != NULL){ if(sizeof(moji) < strlen(moji) + strlen(buf)) break; strcat(moji, buf); }; getchar(); //* //プログラムここまで

  • プログラム問題(3)

    以下の問題のプログラムをやったのですが、コマンドプロンプトで実行してみるとエラーになってしまうのですが、どなたか問題点を指摘していただけないでしょうか? 【問題】 3桁の整数の値を入力していき、-9999が入力されたところで、それまでに入力された数の個数と合計を整数で、平均を浮動小数点数で出力するプログラム。 【プログラム】 #include <stdio.h> #include <stdlib.h> #include <string.h> #define streq(a, b) !strcmp((a), (b)) int main(int argc, char *argv[]) { int i, num, sum = 0; double avg; char buf[256]; char *endptr; for (i = 0;; i++) { printf("INPUT>"); if (fgets(buf, sizeof buf, stdin) == NULL) { perror("fgets"); exit(1); } if (streq(buf, "-9999") || streq(buf, "-9999\n")) { break; } if (streq(buf, "") || streq(buf, "\n")) { fprintf(stderr, "数値を入力してください。\n"); exit(1); } num = (int) strtol(buf, &endptr, 0); if (! (*endptr == '\n' || *endptr == '\0')) { fprintf(stderr, "数値を入力してください。\n"); exit(1); } sum += num; } printf("入力数:%d 合計:%d 平均:%g\n", i, sum, (double) sum / i); return 0; }

  • fgetsを用いたループ処理後の入力について

    http://oshiete1.goo.ne.jp/qa3853689.htmlにて質問した内容ですが、 想定していたソースの範囲内では解決しないことが分かりましたので、新規に立てさせていただきます。 下記でfgetsを使って入力した後についてですが、*2のgetcharを無視して、*1のscanfで入力を受け付けなくなります。 *2のgetscharについては、その個数を増やしても同様に無視されます。 これを解消する方法はないでしょうか? ちなみにコンパイラはBBC、開発環境はVistaです。 なお、簡略のため#includeなどは省略しています。 #define SIZE 16384 void main(void){  int mode,r;  while(1){   do{    r = scanf("%d", &mode); //*1 return後に停止    while(getchar() != '\n'){ };   }while(r == 0)   switch(mode){ //その他選択肢あり    case 1:     execute();     break;   }  }  return; } void execute(void){  char moji[SIZE];  char buf[SIZE];  while(fgets(buf, sizeof(buf), stdin) != NULL){   if(sizeof(moji) < strlen(moji) + strlen(buf))    break;   strcat(moji, buf);  }  while(getchar() != EOF){ }  getchar(); //*2 これを無視して動作(scanfでも同様)  return; }

  • fgetsとsscanfを使って一行から複数入力

    環境はC言語です。 一行から不定数の文字列を入力したいと考えています。 fscanfは使わずに、fgetsとsscanfを使って実現させたいと考えています。 以下ではうまくいきませんでした。 --sorce-- char temp[1024], buf[1024]; while(fgets(stdin, 1024, buf) != NULL)){    //ファイルで標準入力でもどっちも可能  while(sscanf(buf, "%s",temp) != EOF){   printf("%s ", temp);  } } --input-- red blue black yellow white red red red black yellow white blue red blue blue --理想output-- red blue black yellow white red red red black yellow white blue red blue blue よろしくおねがいします。

  • アドレスをint変数に代入する方法

    printfで表示したアドレス値を、int変数に代入するのが目的です。 #include <iostream> using namespace std; main(){ char buf[20]; char *(*pp)[2]; char *p[2]; int i; pp = &p; printf("%lu\n", pp); // i = (int)(&pp); sprintf(buf, "%lu\n", pp);//// i = atoi(buf);//// printf("%lu\n", i); } とりあえずできていますが、 pp = &p;以降の処理で、bufを使ったり非推奨?のatoi()を使っています。 pp = &p;以降の処理でもっとよい方法はないでしょうか? また、このソースは不正なことをやっていないでしょうか? 必要な初期化をやってない、などということはありませんか?

  • fgets, sscanf, バッファ、ストリーム について

    ファイルからデータを入力するのに、fscanf の代わりに fgets と sscanf を用いようと考えています。 そこで、sscanf に与えるバッファ文字列を、ファイルストリームのように扱う方法は無いものでしょうか。 例えば以下のデータファイルに対して、以下のプログラムをうまく動作させるには、どのようにすればよいでしょうか。 どうぞ、よろしくお願いします。 (データファイル test.dat) n_data 4 1 3 8 4 (プログラム) #include <stdio.h> main() { int i, n_data, *data; char buf[100]; FILE *fp; fp = fopen ( "test.dat", "r" ); fgets(buf, 100, fp); sscanf( buf, "n_data %d\n", &n_data ); data = (int *)malloc( n_data * sizeof(int) ); for( i=0; i<n_data; i++ ){ fgets(buf, 100, fp); sscanf( buf, "%d", &(data[i]) ); } sscanf( buf, "\n" ); close( fp ); printf( "n_data %d\n", n_data ); for( i=0; i<n_data; i++ ) printf( " %d", data[i] ); printf( "\n" ); } ちなみに、2行の fgets(buf, 100, fp); をコメントアウトして、 "sscanf( buf," を "fscanf( fp," に変更するとうまく動作します。

専門家に質問してみよう