- ベストアンサー
ソケット通信内 read関数について
現在C言語にソケット通信を作成しているのですが、read関数内の作成でつまずいています。 ご存知でしたら教えてください。 自分なりに調べた結果read関数の戻り値は受信した バイト数、毎回指定サイズ受け取るとは限らないと いうことでした。 そこでread関数を無限ループで回し 指定サイズ受信したら、ループを抜ける使用にしたのですが、受信バイトが0だった場合はどうすればよいのでしょか? よくサンプルなどでは、0だったらエラーと判断し、すかさずbreakしているのですが、一度でも0バイトを受信すると、それ以降は1バイト以上受信出来ないものなのでしょうか? もし出来ないのなら一度でも0を受信したら、breakしようと思っています。 出来るのでしたら、タイマー設定をし、指定受信バイトに満たなくても一定時間が過ぎたらループから抜ける使用にしたいと考えています。 そのほか良い方法があれば教えてください。 分かりずらい説明になってしまいましたが、宜しくお願い致します。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
selectの戻り値が1となったのならば一歩前進です。 あとは、FD_ISSET()して期待通りのソケット番号にデータきていれば受信できると思います。 ところで今回のソースでFD_SET()のところはどうなっていますか? selectでいつも0となるのはFD_SETがちゃんとできていないような気がします。 前回と今回のソースで差分をチェックしてみてはどうでしょうか。 がんばってください! あと、ほかに参考になりそうなページをのせてみます。 「selectを使う」の項目が役立ちそうです。fdという変数にaccept()した戻り値を入れるようにすればいけます。
その他の回答 (6)
- nazo-nazo
- ベストアンサー率39% (17/43)
No6です。 別方法ですが、ソケットオプションを指定する方法もあります。 //ディスクリプタにタイムアウト設定 setsockopt(socketfd,SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)); if(read()<0){ if(errno==EWOULDBLOCK){timeout} }
お礼
お礼遅れまして申し訳御座いません。 上記の方法はまだ、試していないのですが、 ずっとselectの戻り値が0だった理由が分かりました。 select関数を使用する際、if((qq=select(fd,NULL,NULL,NULL,&time)) == xxx){ みたいにifの 判定をしていました。 そこで、ifをとったところ1が帰ってくるようになりまいした。 どうも有難う御座いました。
- nazo-nazo
- ベストアンサー率39% (17/43)
間違っていた場合は、すみません。 例えば、 タイムアウト:10秒 指定サイズ:100バイト 8秒置きに1バイトづつ送った場合、10秒でタイムアウトされないような気がします。
お礼
ご指摘ありがとう御座います。 僕の説明不足でした。 確かに全部のデータが届く時間が10秒ではなく、 10秒以内に何バイトでもデータが届けば タイムアウトされませんでした。
- emonky
- ベストアンサー率28% (18/63)
タイムアウトの設定をしない場合は、待ち時間が0となり、すぐにタイムアウトしてしまいselectの戻り値が0になると思います。 参考にされているソースだとaccept()できたらプロセスを作っていますが、とりあえず通信したいのであれば同じ関数内ですませてしまうというのもできると思います。 サーバソケットsocket生成 listen() ↓ accept() ↓ while(1) { select() ↓ recv() } としてみたらいかがでしょうか。
お礼
emonkyさん何度もお助け文有難う御座います。 一応こちらの中間状況をお知らせ致します。 上記でアドバイスを受けた通り、なるべくシンプルな コードにしてみました。 しかし、結果は変わらず。。。 そこで同サイトにselect関数内でタイマーを使用したサンプルコードがあったのでそちらを動かしselectの戻り値を確認したところ1が帰ってきました。 試しにそのサンプルからタイマー設定の時間を0に 設定したり、select関数の第5引数をNULLにセットしたところ、それでも1が帰ってきてしまいました。 このような切り分け作業を行ったのですが、あと他に考えられることはありますでしょうか?
- emonky
- ベストアンサー率28% (18/63)
とことん行きましょう!!(^^; selectの結果がいつも0というのは受信イベントがみつかってなくタイムアウトしています。 私の書いたソースでsockとありますが、この変数にはrecv()で使う引数と同じソケット番号が入っていなければいけません。 ちなみに、私はTCPで接続を行っているものと思い込んでいますがあっていますか?? TCPでやろうとしているのならば、FD_SET()する時点で相手と接続できていると思いますのでそのソケット番号を使ってください。 つまり、サーバ側であればaccept()したときの戻り値が受信で使うソケット番号となるのでFD_SET()もこの値を使う。クライアント側であればconnect()で使用したソケット番号となります。
お礼
返事が遅れ、申し訳ありません。 一応emonkyさんがおっしゃている通りの設定になっていると思います。 現在、僕が参考にしているサンプルです。 http://hp.vector.co.jp/authors/VA003991/kouza/senior/kouza_socket.html 上記サンプルはselectでタイムアウトの設定はして いないのですが、これにemonkyさんが教えてくれました、コードを追記しました。 補足ですが、タイムアウトの設定をしない状態でも select関数の戻り値は0でしたが、これは正常なので しょうか?
- emonky
- ベストアンサー率28% (18/63)
#1:emonkyです selectの説明は参考URLでお願いします。 2番目の引数に設定するのはあっています。2番目の引数は受信のイベントについてチェックします。 5番目の引数にタイムアウト時間の設定をします。 selectでタイムアウトが発生すると戻り値が0となります。 簡単なソースの流れを書いておきます。 参考にして組んでみてください。 fd_set recvFDs; struct timeval tv; FD_SET(sock, &recvFDs); tv.tv_sec= 5; /* 5sec */ tv.tv_usec=0; ret = select(sock+1,&recvFDs,0,0,&tv); switch(ret) { case -1: /* error */ break; case 0: /* timeout */ break; defualt: if(FD_ISSET(sock,&recvFDs)) { recv(); } }
- 参考URL:
- http://www.linux.or.jp/JM/
お礼
例文まで記述して頂き有難う御座いました。 一応意味を理解し、上記の通りにプログラムを書いて みたのですが、どうしてもselect関数の戻り値が0になってしまいます。試しに第5引数をNULLに戻しselect関数を実行させたのですが、これも変わらず戻り値は0で、正常終了していまいした。何が原因でしょうか?
- emonky
- ベストアンサー率28% (18/63)
readの戻り値が0だった場合は、接続相手とのコネクションが終了しています。TCPのFINを受信したときに0になったような・・ 一定時間でチェックしたいということならばselectという関数を使用したらどうでしょうか? ここではselectの使い方はいたしませんが、詳細を希望ならまた説明したいと思います。
お礼
迅速な回答ありがとうございました。 selectは使用しているのですが、サンプルを真似たのでしっかりとした使用方法が分かりませんのでご教授ください。 また、現在selict内の第3~5引数はNULLがセットされています。 以上、宜しくお願い致します。
お礼
またまた中間報告です。 http://yonex1.cis.ibaraki.ac.jp/progai4/public_html/page11.htmにあるサンプル(チャットプログラム)でタイムアウトを10秒に設定し、クライアントからのデータ送信を10秒以内、10秒以外で確認した結果、以内の戻り値は1、以外の戻り値は0になりました。これがemonkyさんのおっしゃっていたタイムアウト設定だと思います。