• 締切済み

recvfrom関数の戻り値について

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

  • rom1
  • お礼率0% (0/8)

みんなの回答

  • 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

  • main関数の戻り値

    C言語のmain関数の戻り値はint型ですよね。 私もそういう決まりだと思って守ってきました。 しかし、「mainが戻り値を返すって、どこに返すの?」ということが、私は理解できていません。 私が調べたところでは、「ホスト実行環境」という言葉がこの問題に関係あるようですが、この言葉の意味はよくわからないですし、似た言葉で「ホスト環境」ということばがあるのですが意味も関係もわかりません。 これらは、OSとは違うと思うんですが、自信はありません。 それでも、ない知識を振り絞っていろいろ考えてみると、次のようなことらしいのですが、正しいでしょうか。 ・OSはプログラムの実行に先立ちホスト実行環境を作る。 ・静的記憶域のオブジェクトを初期化するのはホスト実行環境である。 ・関数が、main関数を呼ぶことは可能である。(以下では、main関数が関数から呼ばれる場合は除く。) ・main関数を呼ぶのは、ホスト実行環境が行なう。 ・main関数の中のreturnによってプログラムが終了するのと、exit関数でプログラムが終了することに違いはない。 ・main関数の戻り値は、ホスト実行環境に返される。 ・returnによってホスト実行環境に返される値は、int型である限りなんでもよい。 ・exitによってホスト実行環境に返される値は、int型である限りなんでもよい。 ・必ずexitで値が返されるならば、main関数の中にreturnはなくてもよい。 main関数からの戻り値をどうしようと構わないんだと思うんですが、皆さんの経験の中で、実例としてこういうふうに使われる、というのは何かないのでしょうか。 (ホスト実行環境に値が返される、といっても無視するのでは意味はないと思うのです。 その値の使用例としては、 0が返ってくると「プログラムは正常終了しました。」と表示するとか、0以外の値が返されると別のプログラムが走るとか、 そういうことだと思うんですが。)

  • recvfrom関数の戻り値がおかしいんですが…

    初めて投稿させていただきます。 現在、Cにてあるクライアントプログラムを作成している者です。 構成は以下の通り。 《構成》 サーバ:PLC(シーケンサと書けば大体の方はわかりますか?) クライアント:Linux Ubuntu9.10 通信方式:TCP/IP 《開発環境》 言語:C IDE:eclipse コンパイラ:gcc 4.x 《質問》 クライアントプログラムからASCIIデータをサーバへ送信し、サーバはクライアントから受信したASCIIデータに応答し、ASCIIデータ伝文を返信してきます。 このサーバからのASCIIデータ応答伝文をrecvfrom関数で受信し、応答伝文のASCIIデータを'buf'変数に格納し、標準出力関数で表示させるといったプログラムです。 このプログラムでは、ユーザ関数内でrecvfrom関数をコールしているのですが、ユーザ関数内でrecvfrom関数をコールした場合、受信データの先頭4byteしか受信できておらず、困っています。 ちなみに、main関数内でrecvfrom関数をコールすると、応答伝文全体のデータをきちんと受信できています。 ちなみに、サーバの応答ASCIIデータ伝文は、仕様通り(期待通り)のデータが返信されています。(ネットワークモニタ:wiresharkで確認済み) recvfrom関数をコールする場所によって、変数に格納するデータ量が変わるといったことがあるのでしょうか。 ソースの一部を添付します。 参照の上、アドバイス等いただけないでしょうか。 《ソース》 ◆mainソース #include ... :<-#include定義 int main{   :<-変数定義、変数初期値代入処理等 ユーザ関数1()コール<-ユーザ関数1内でソケット通信処理を動作させている。 ユーザ関数2()コール<-同上 } ◆ユーザ関数用ソース #include...   :<-#include定義 unsigned char ユーザ関数名1;<-ユーザ関数プロトタイプ宣言 unsigned char ユーザ関数名2:<-同上 char 変数1[5]; char s_buf[4096]; char buf[4096]; /*データ受信用バッファ*/ char 変数2[256]; size_t len; long l; int sock_fd; /*ソケット用ファイル記述子*/ struct sockaddr_in cl_addr; /*CPU用ソケットアドレス*/ socklen_t cl_len = 0; /*cl_addrのサイズ格納用*/ ssize_t n = 0; unsigned char ユーザ関数1(char *引数1,…char *引数5){   :送信データ生成処理 //* ソケット作成 *// if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1;   } //* 接続先定義*// memset(&cl_addr, 0, sizeof cl_addr); cl_addr.sin_family  = AF_INET; /*プロトコル定義*/ cl_addr.sin_addr.s_addr = inet_addr("***.***.***.***"); /*IPアドレス定義*/ cl_addr.sin_port  = htons(****); /*Port定義*/ //* 接続 *// if (connect(sock_fd, (struct sockaddr *)&cl_addr, sizeof cl_addr) < 0) { perror("connect"); return 1;   } //* データ送信 *// if(send(sock_fd, s_buf, strlen(s_buf), 0) < 0){ fprintf(stderr, "could not send message : %s\n", s_buf); exit(EXIT_FAILURE); } printf("\nSendMessage\n%s\n",s_buf); //* データ受信 *// cl_len = sizeof cl_addr; //*↓↓このrecvfrom関数でbuf内にサーバ応答伝文の先頭4byteのみが格納されている。↓↓*// if (( n = recvfrom(sock_fd, buf, sizeof buf,0, (struct sockaddr *)&cl_addr, &cl_len)) < 0) { perror("recvfrom"); return 1; } fprintf(stderr ,"TCP from addr = %s, port = %d\n", inet_ntoa(cl_addr.sin_addr), ntohs(cl_addr.sin_port) );

  • 戻り値と引数

    戻り値と引数の概念がよくわかりません。 質問内容は2つ (1)「戻り値は値を関数元に返す」 とありますが 返すとどうなるのですか? また返さないとどうなるのかを教えて下さい。 (2)引数に関しては眺めていればこの引数が値を渡してるというのは なんとなくわかるのですが、実際のプログラムを組んで関数を作成するときに何を引数にすればいいのかさっぱりです。それを教えて下さい。

  • ソケットのrecvの戻り値が0

    linuxにてソケットの勉強をしようと思い、 簡単なソケット通信のプログラムをCで組みました。 ret = recv(ID, Buff, sizeof(Buff), 0); といった感じでサーバ側を組んだのですが、 この戻り値retに0が入ることがあり、思うように動いてくれません。 私の認識だと、recvは受信するまで待ち、 受信したサイズを返すと思っているのですが、 それが0とは、いったいどういう意味を持つのでしょうか?

  • 関数で複数の値を戻り値として返す方法

    こんにちは初歩的な質問ですいませんが、VB6.0にて関数を 呼び出して、求めた値を戻り値として返す方法は知ってい ますが、2つ又は3つの値を返したい場合、どうやればよい のでしょうか? よろしくお願いします。

  • 関数内で数値入力したときの戻り値は?

     数値を入力して変数に格納する、という作業を複数回繰り返すような数値入力のための関数をつくったとします。そのような場合、関数の宣言や戻り値はどのようにすればよいのでしょうか?  グローバル変数を用いたときにはうまくいったのですが、ローカル変数にかえようとしたらmain関数の中で値が割り当てられていません、となってしまいました。  教えてください。お願いします。

  • C言語 関数の戻り値と自動変数

    かなり基礎的な質問になるのですが、疑問に思うことがあり、質問をさせていただきます。 関数内で宣言した変数を戻り値として使う場合ですが、ポインタなどではなく実体の場合でも、静的変数として宣言をしたほうが良いのでしょうか? 現実的に考えると、プログラムが関数から出て、呼び出した側の関数が戻り値を受け取るまでの瞬間に、その領域が書き換えられる可能性は極めて低いと思うのですけど、C言語の仕様としてはどうなのでしょうか? 関数内で宣言した戻り値に使う変数には、必ずstaticをつけた方が良いのでしょうか? もしおわかりでしたら教えて下さい。

  • 配列を関数の戻り値に使う

    こんばんわ。 PHP5で配列を関数の戻り値として返す方法がわからず今回投稿させていただきました。 配列は1次元で 1,2,3 の値が a という配列に格納されています。 呼び出された関数(testメソッド)で a配列を返し、bで受けようとするのですが、bの値には NULL となっています。 返す際に return $a; としており、 $b=$obj-〉test(); で、aをbで受けようと考えております。 配列を返す場合は普通にretuneで返すだけではダメなのでしょうか。 解決方法がお分りの方がいらっしゃいましたらご教授のほうおねがいします。

    • ベストアンサー
    • PHP
  • 関数について

    協力お願いします。 2問あります 1問目です。 西暦年yearを引数として受け取り, 閏年かどうかの判定結果を戻り値として返す関数leap_year()を作成せよ. ただし,leap_year()は,閏年の場合は1を返し, そうでない場合は0を戻り値として返すものとする. 提出するプログラムは,関数leap_year()だけでなく, メイン関数main()も含む下記プログラムを完成させる形で作成する。 #include <stdio.h> /* ここに関数leap_year()のプロトタイプ宣言を記述する */ int main() { int i, year[3]; for (i=0; i<3; i++) { printf("西暦年を入力してください"); scanf("%d", &year[i]); if (leap_year(year[i]) == 1) { printf("閏年です.\n"); } else { printf("閏年ではありません.\n"); } } } /* ここに関数leap_year()を定義する */ 2問目です。 mのn乗を計算する関数power()を作成せよ. ただし,関数power()はm,nを引数とし, 戻り値としてmのn乗の値を返すものとする. m,nは,正整数とする.プログラムには, 関数power()だけでなく,m,nを入力し, mのn乗を出力するメイン関数main()を含むものとする. main()は,power()の前に記述すること. また,power()のプロトタイプ宣言も記述すること。 よろしくお願いします。

  • シリアル通信でのread関数の戻り値

    オムロン製PLCと上位コンピュータをRS232Cで接続し、FINSコマンドを用いてシリアル通信をしようとしています。 現在作っているプログラムの流れは、 ・シリアルポート"/dev/ttyS2"のオープン   comm_fd = open("/dev/ttyS2", O_RDWR | O_NOCTTY); ・通信設定   termios構造体を設定 ・コマンドフレーム(COMMAND)を作成し、ポートに書き込む   write(comm_fd, &COMMAND, strlen(COMMAND)); ・PLCからのレスポンスを読み出す   read(comm_fd, &RESPONSE, 256); のようにしているのですが、read関数が実行されたままになってしまいます。(エラーコードも返ってこない状態です) readの戻り値が-1ならポートにアクセスできていないとわかるのですが… ためしにcomm_fdと違う値をread関数に入れてみたところ(read(6, &RESPONSE, 256)、戻り値は-1となりました。 これはどういう状態になってしまっているのでしょうか? わかりにくい質問で申し訳ありません。

専門家に質問してみよう