• 締切済み

recvfrom関数の戻り値について

初めて質問させて頂きます。 現在、LinuxのUnixドメインを使用した内部通信プログラムを 作成しているのですが、recvfrom関数の戻り値で-512という値が 返ってきて頭を悩ませています。 いろいろなHP等でrecvfrom関数の戻り値について記述されている内容は 受信サイズか-1となっているのですが・・・-512という値については さっぱりでした。 -1の場合は、errnoが入るようなのですが、-512の場合、errnoが0のままで何もはいっていないように見えます。 どの様な問題が発生しているかの見当もつかない状態です。 すみませんが、宜しくお願い致します。

みんなの回答

  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.8

ANo6です。 Ano.7に同意見です。 Ano.1の補足に掲載された部分のプログラムには特に問題なく他の部分に問題があってデータの累積受信量が増えるにつれ、なにかおかしなことが起きているように思えます。 ためしに、rcvfromでデータを受信して何もせずに捨てるだけのプログラムを書いて(現在のプログラムから該当部分以外を削って作って)、テストしてみたらどうでしょうか。 それでも症状が変わらないようなら、ライブラリやカーネルのバグ/メモリリークかもしれません。

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.7

再度 ANo.5 です。 「早速内容ですが、sizeof(svr_addr.sun_family)を対象にしたのは、 linux/un.hにてstruct sockaddr_unの定義が struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ }; となっていたためです。」 ですが、これは今回は(多分)正しいですが、一般的には正しくない可能性もあるので注意してください。私の理解では、構造体のメンバー変数鵜の順序はプログラムで書いた通りですが、メンバー変数の間が必ず「詰まった」状態となるかどうかは、つまり「空き」が生じる可能性があるかもしれない、処理系や機種依存だと思います。ということで、SUN_LENを使うのが一番正しいですね。 で、本題ですが、私の直感では、どこか他の部分で悪さしているように思いますので、これ以上、新たな情報がない限り、進展はみられないでしょう。

  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.6

症状からすると、どこかにバグがあってスタックを破壊しているっぽいのですが。あるいはglibcを入れ替えたとかの副作用?(考えにくいですが) 「何百回と正常に動作していたものが急にメモリ破壊を 起こすことはあるのでしょうか?」 というところをもうちょっと説明して貰えませんか。 プログラムをまったく変更しないのにある日急に変になったのでしょうか?再コンパイルはしていませんか?カーネルやライブラリの入れ替えはしていませんか? 少なくとも、デバッグのためのprintf文を入れるというだけの変更でも、メモリ破壊系の症状は変わったりしますので油断ならないです。 なお、 islen = sizeof(rcv_addr.sun_path); は islen = sizeof(rcv_addr); ではないですか?今回の場合これで害はないと思いますが。 あと、int main(・・なんですからreturn;ではなくて return 1;(エラー終了の場合)としたほうが気持ちいいですね。

rom1
質問者

補足

ご回答ありがとうございます。 再コンパイル等についてですが、本問題発生後にデバッグ情報出力 強化等の改造は実施いたしましたが、問題発生時の再コンパイル等 はありません。また、その改造後も現象が発生しております。 カーネル・ライブラリの変更はありません。 「何百回と正常に動作していたものが・・・」というあたりが 紛らわしい表現だったかと思いますが、動作確認のために問題箇所に 対して大量にイベントを送信し続けるといった試験をいたしました。 その結果最初は正常に受信できるのですが、数時間後に本問題が 発生して受信エラーになってしまいます。 問題が発生するまでの時間はまちまちで、11時間かかることもあれば 1時間程度で発生することもあります。 returnに関しましては・・・重ね重ねすみません。

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.5

「メモリの破壊ですか、その可能性はありそうですね。 ただ、理解が不足しているだけなのかも知れませんが、 何百回と正常に動作していたものが急にメモリ破壊を 起こすことはあるのでしょうか?」 ということは問題が起きているのはこのプログラムではないということなのかな? いずれにせよ、私が書いた(でも忘れてしまっていた)動いている(ハズ)のコードでは、長さの計算を、 #ifdef SUN_LEN /* derived from 4.4BSD */ *size = SUN_LEN(sock_addr); #else *size = sizeof(struct sockaddr_un) - sizeof(sock_addr->sun_path) + strlen(sock_addr->sun_path); #endif としていますね。また CentOS での SUN_LEN の定義は # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path)) となっていて(ちょっとトリッキーですが)上の私の定義と基本的に同じです。 ilen = strlen(svr_addr.sun_path) + sizeof(svr_addr.sun_family); ですが、sizeof(svr_addr.sun_family) はやっぱりおかしくないですか?svr_addr.sun_family は sum_family_t になっていて、この定義は linux/socket.h:typedef unsigned short sa_family_t; ですから。

rom1
質問者

補足

ご回答ありがとうございます。 まず、返信が遅れまして申し訳ありません。 早速内容ですが、sizeof(svr_addr.sun_family)を対象にしたのは、 linux/un.hにてstruct sockaddr_unの定義が struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ }; となっていたためです。 また、ご指摘のとおりbind時のサイズ指定にてSUN_LENを使用して みたのですが、問題の現象が再現してしまいました。

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.4

ちょっとお酒も入って検証するのが面倒なのですが、 ilen = strlen(svr_addr.sun_path) + sizeof(svr_addr.sun_family); ですが、こんなことしたっけかなぁ(でも自信なし)。 ひょっとしてメモリ壊してませんか?-512 ですから最初の2バイトがクリアされてる? buf とか sockaddr とかを main の外に出してみるとどうなりますか?あるいは ret の前に適当な配列を入れてみるとか、変数の順序を変えてみるとか。 余談ですが、最後の return に値がないのは気持ち悪いです。

rom1
質問者

補足

ilenの計算ですが、bind関数の第4引数は、第3引数のサイズと あった為、上記処理でサイズを求めて設定してます。 メモリの破壊ですか、その可能性はありそうですね。 ただ、理解が不足しているだけなのかも知れませんが、 何百回と正常に動作していたものが急にメモリ破壊を 起こすことはあるのでしょうか? 最後にreturnに値がないことについて・・・ 元々void main()って形が好きだったんですが、コンパイル時にvoidだと警告が出てしまうのでintに強制したんですが・・・ 癖が抜けなくて^^;

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

こちらの環境でそのソースをコンパイル&リンクして実行しました。 正常に動作しています。(INTEL-solari10 sun-studio-11 でコンパイル) linux(CENTOS4.4) のgcc(3.4.6)では、コンパイルエラーのため確認出来ませんでした。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

どのような確認のしかたで戻り値が-512であると、判断したのでしょうか。 ssize_t ret; ret=recvfrom(...); printf("ret=%d\n",ret); 上記のように確認していますか。正しく戻り値を判定していないように思われます。 ssize_tは訳の分からないサイズですが、sizeof(ssize_t)が4ですので、int型と考えて良いでしょう。

rom1
質問者

補足

下の回答でも記述したのですが、intデータに戻り値を格納し、 %dで表示しております。 但し、戻り値の格納先についてはintデータを使用しており、 ssize_tを使っていないのですが、戻り値の格納サイズに関しては 共に4バイトデータの為、問題ない気がしております。

  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.1

カーネルが壊れているか、あなたのプログラムが間違っているかです。 当然後者でしょうけど。 そもそもなぜ-512という戻り値であると判断したのでしょうか? プログラムの当該部分を示してください。 recvfromの返り値を shortの変数で受けたりしてないですよね。

rom1
質問者

補足

戻り値を%dで表示した時、-512と表示されました。 又、戻り値の格納先はintの変数にしております。 unsigned intではないので-512と表示されました。 又、長くなってしまうのですが、該当処理は以下の通りです。 #define SNDSOCKPATH "./sock_file" int main(int argc, char *argv[]) { struct sockaddr_un svr_addr; struct sockaddr_un rcv_addr; int socka = 0; int ilen = 0; int c = 0; int islen = 0; int ret = 0; int en; char buf[4096]; char pbuf[256]; socka = socket(AF_UNIX, SOCK_DGRAM, 0); if(0 > socka) { printf("a socket err %d\n", errno); return; } unlink(SNDSOCKPATH); memset(&svr_addr, 0, sizeof(svr_addr)); svr_addr.sun_family = AF_UNIX; strcpy(svr_addr.sun_path, SNDSOCKPATH); ilen = strlen(svr_addr.sun_path) + sizeof(svr_addr.sun_family); if(bind(socka,(struct sockaddr *)&svr_addr, ilen) < 0) { close(socka); unlink(SNDSOCKPATH); return; } while(1) { en = 0; errno = 0; memset(&rcv_addr, 0, sizeof(rcv_addr)); memset(pbuf, 0, sizeof(pbuf)); islen = sizeof(rcv_addr.sun_path); ret = recvfrom(socka, (char *)&buf, sizeof(buf), 0, (struct sockaddr*)&rcv_addr, &islen); en = errno; perror(pbuf); printf("recvfrom ret[%d] errno [%d(0x%08x)] "\ "sun_path[%s] sun_family[%d]\n", ret, en, en, rcv_addr.sun_path, rcv_addr.sun_family); } return; } -512を判断したのは、戻り値retを参照した為です。

関連するQ&A