• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:send-recvで複数データの送受信)

send-recvで複数データの送受信する方法と問題点

このQ&Aのポイント
  • WindowsVista VC6とLinux2.6.18-at9 Debian PowerPCでunsigned longのデータ数千個を順次送受信するプログラムを作成していますが、問題があります。
  • 受信側のループにprintfやsleep(1)を入れないと受け取れないという現象が発生しています。
  • また、毎回内容ゼロのデータがもう一つ加わるという問題も発生しており、データ量が2倍になってしまいます。

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

  • ベストアンサー
  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.5

>テーマはずれてきているのですが、スレッド間で変数の変化をリアルタイムで検出する方法が分かりません。 >Mainスレッドでは受信スレッドの状況をcountで見ています。 volatileを使用。というのが最初に浮かぶ方法ですかね。 http://d.hatena.ne.jp/yupo5656/20040618/p1 という意見もあるので微妙ですが。 # Linuxでマルチスレッドプログラミングしたことないので…。 >sleep(1)を使っていたのですが、遅いですし 1秒では遅い…でしょうね。 nanosleep()使ってみたらどうでしょうか? http://archive.linux.or.jp/JM/html/LDP_man-pages/man2/nanosleep.2.html 引数で指定する時間はもう少し考慮が必要かも知れませんが。

gammodler
質問者

お礼

Wr5様 nanosleep試みてみました。 両方のスレッドに200μsのnanosleepをいれたとことろ全体としては動作するのですが、DATANOに達する直前で受信スレッド内のループを回らなくなります。 この原因はわかっていません。 それにあと二桁短縮しないと仕様に合いません。しかし最初から起動しなくなります。 他の方法を試みて問題を整理の上再度質問させていただきます。 ありがとうございました。

その他の回答 (4)

  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.4

>1回目に'1','2','3','4','5','6','7','8','9','0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'を送信。 >1回目に'1','2','3','4','5','\0','7','8','9','0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'を送信。 1回目に~ 2回目に~ の間違いです。

  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.3

>sprintf(buf, "%d", dataBuf); >ok = send(s, buf, sizeof(buf), 0);// Blocking Mode ? 1回目に'1','2','3','4','5','6','7','8','9','0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'を送信。 1回目に'1','2','3','4','5','\0','7','8','9','0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'を送信。 という感じにゴミデータも送るのは仕様ということでよろしいですか? # 2回目に送ったつもりのデータをrecvで先頭から7バイト受信していたら、続くゴミデータが有効データとして処理される可能性がありますが… memset(buf, '\0', sizeof(buf)) 等で明示的にクリアしておくべきです。 また、既に回答着いていますがrecv()の戻り値はちゃんと確認するべきです。 「send()で10Byte送ったからrecv()で10Byte指定すればちゃんと10Byte受信できる。」 と思っているのでしたら、『そうとは限らない』というコトを考えておいた方がいいです。(ストリームですし…) # まぁ、指摘されている通り、(ゴミデータ付きで)20Byte送って、(最低でも)10Byteを2回という受信を行っているので… # ループの2回目ではゴミデータをatol()に渡して0が代入されている…でしょう。(もちろん、ゴミ次第で0以外が入りますが) >1.受信側ループにprintf、sleep(1)等を入れないと受からない。 > なお受信側はMainとは別のスレッドにしています。 スレッド切り替えが発生しない(タイムスライス使い切るまで切り替わらない?)ので、受信データをバッファから受け取れないのでしょう。 printf()でいけるのは、カーネルのシステムコールが発生した時点でスレッド切り替えが走っているのでしょう。 >2.毎回内容ゼロのデータがもう一つ加わってしまう。 > recvが毎回データ到着までBlockつまり待ちにしていると期待したのですが、2回通り抜けたような効果があり、各データにゼロデータがもう一行付加されてしまう。つまりデータ量が2倍になる。 既に指摘した通りです。 有効データ+ゴミデータで20byte送り、受信側では有効データ(10Byte)+ゴミデータ(10byte)をatol()に突っ込みます。 # recv()で10Byteのデータが受け取れなかった時はさらにヘンなことになります。 # ゴミデータ次第でSegmentation Fault発生します。

gammodler
質問者

補足

Wr5様 Resありがとうございます。 データ量が2倍になってしまう件はひとつ前で報告しましたように解決しました。 テーマはずれてきているのですが、スレッド間で変数の変化をリアルタイムで検出する方法が分かりません。 Mainスレッドでは受信スレッドの状況をcountで見ています。 while(count < DATANO){ printf("count %x\n", count); // sleep(1); } count = 0; // Burst転送終了 ・・・・・ sleep(1)を使っていたのですが、遅いですし受信スレッドのcountをモニタする機能はprintf文で代用できることがわかったので代替しました。 一方受信スレッド側もタイムスライス分を使い切る前にMainから見えるようにするにはシステムコールを使わなければならないことが分かりました。問題点として: 1.非常に低速、printf文は省きたい。 2.なぜか所定数(DATANO)分受信のスレッドを回らず、countの値が少し手前で変化しなくなる。つまり受信スレッドのwhileループを抜けなくなります。 printf文挿入により低速化、送信側と同期せず受信バッファが切り捨てられているのではと推察しています。 この二つの困難はどう克服すればいいのでしょうか?。マルチスレッドは殆ど初めて。見当がつきません。 お教え願えれば幸いです。

  • trapezium
  • ベストアンサー率62% (276/442)
回答No.2

自分でこう書いたけど、 > recvSize == sizeof(buf) になってるかは一応見たほうがいいんじゃないかな。完全に挙動が把握できてるならいいけど。 やっぱり send したバイト数 recv されるまで、recv() 繰り返すように書くよな。 かなり頭回らず。

  • trapezium
  • ベストアンサー率62% (276/442)
回答No.1

> char buf[20]; > ok = send(s, buf, sizeof(buf), 0);// Blocking Mode ? ここで 20 バイト send して > char buf[10]; >  recvSize = recv(conn_fd, buf, sizeof(buf), 0);// Blocking Mode 10 バイト recv してるように見えるけど? それに block してるとはいえ、 >  if(recvSize == 0){ >  else if (recvSize == -1) { recvSize == sizeof(buf) になってるかは一応見たほうがいいんじゃないかな。完全に挙動が把握できてるならいいけど。

gammodler
質問者

お礼

trapezium様 ご指摘の通りでした。 PC側をchar buf[10]とすることでデータ数が一見2倍になってしまう問題、解決しました。 else if(recvSize != sizeof(buf)){ printf("recvSize sizeof(buf) %x %x\n",recvSize, sizeof(buf)); recvSize = recv(conn_fd, buf, sizeof(buf), 0); } としていますがこのエラーは出力されません。 recvの仕様をよく確認していませんでした。 ありがとうございました。