初歩的な質問で恐縮ですがよろしくお願いいたします。
send側 :WindowsVista VC6
recv側 :Linux2.6.18-at9 Debian PowerPC
でunsigned longのデータ数千個を順次送受信するプログラムを組んでいるのですが不調です。
ともにBlockingモードで動作しているのだから双方にWhileループを組めば特段のHandShakeは不要で受信側所定バッファに逐次取り込めるのだと思っていました。しかし:
1.受信側ループにprintf、sleep(1)等を入れないと受からない。
なお受信側はMainとは別のスレッドにしています。
2.毎回内容ゼロのデータがもう一つ加わってしまう。
recvが毎回データ到着までBlockつまり待ちにしていると期待したのですが、2回通り抜けたような効果があり、各データにゼロデータがもう一行付加されてしまう。つまりデータ量が2倍になる。
プログラム:
送信側:
SOCKET s;
unsigned long dataBuf
char buf[20];
int ok;
while ( count < DATANO) ){
fread(&dataBuf, sizeof(dataBuf),1,fp); // ファイルより読込み
sprintf(buf, "%d", dataBuf);
ok = send(s, buf, sizeof(buf), 0);// Blocking Mode ?
if(ok==SOCKET_ERROR){
printf("Command送信不良");
exit(1);
}
count++;
}
受信側:
void* dataReceiveThread(void* pParam)
{
char buf[10];
int recvSize, count = 0;
unsigned long val, memBuf[4096];
while(1){
memset(buf, 0, sizeof(buf));
recvSize = recv(conn_fd, buf, sizeof(buf), 0);// Blocking Mode
if(recvSize == 0){
printf("conn_fd broken by Host\n");
close(conn_fd);
break;
}
else if (recvSize == -1) {
perror("recv");
exit(EXIT_FAILURE);
}
val = atol(buf);
⇒ printf("val %x\n", val);
if (count < DATANO){
memBuf[count] = val;
else
break;
count++;
}
このプログラムは初回のデータは問題なく受信できます。
以降のデータは⇒でループ速度を下げないと受信できません。しかしこれは仕様に合いません。
ただしデータ量が2倍になってしまうのでFlipFlopを入れてループを間引いて強引に辻褄合わせをしたところデータはそれらしく受信できます。しかし指定回数ループできません。
recvのBlock機能を誤解しているのかもしれない考え、selectを入れるなどしたのですが解決しません。send-recvの基本仕様を理解していないためと思われます。
ご教示願えれば幸いです。
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 …
引数で指定する時間はもう少し考慮が必要かも知れませんが。
Wr5様
nanosleep試みてみました。
両方のスレッドに200μsのnanosleepをいれたとことろ全体としては動作するのですが、DATANOに達する直前で受信スレッド内のループを回らなくなります。
この原因はわかっていません。
それにあと二桁短縮しないと仕様に合いません。しかし最初から起動しなくなります。
他の方法を試みて問題を整理の上再度質問させていただきます。
ありがとうございました。
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回目に~
の間違いです。
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発生します。
この回答への補足
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文挿入により低速化、送信側と同期せず受信バッファが切り捨てられているのではと推察しています。
この二つの困難はどう克服すればいいのでしょうか?。マルチスレッドは殆ど初めて。見当がつきません。
お教え願えれば幸いです。
No.2
- 回答日時:
自分でこう書いたけど、
> recvSize == sizeof(buf) になってるかは一応見たほうがいいんじゃないかな。完全に挙動が把握できてるならいいけど。
やっぱり send したバイト数 recv されるまで、recv() 繰り返すように書くよな。
かなり頭回らず。
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) になってるかは一応見たほうがいいんじゃないかな。完全に挙動が把握できてるならいいけど。
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の仕様をよく確認していませんでした。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・「みんな教えて! 選手権!!」開催のお知らせ
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~1/20】 追い込まれた犯人が咄嗟に言った一言とは?
- ・洋服何着持ってますか?
- ・みんなの【マイ・ベスト積読2024】を教えてください。
- ・「これいらなくない?」という慣習、教えてください
- ・今から楽しみな予定はありますか?
- ・AIツールの活用方法を教えて
- ・【選手権お題その3】この画像で一言【大喜利】
- ・【お題】逆襲の桃太郎
- ・自分独自の健康法はある?
- ・最強の防寒、あったか術を教えてください!
- ・【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
- ・歳とったな〜〜と思ったことは?
- ・ちょっと先の未来クイズ第6問
- ・モテ期を経験した方いらっしゃいますか?
- ・好きな人を振り向かせるためにしたこと
- ・【選手権お題その2】この漫画の2コマ目を考えてください
- ・【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
教えて下さい
-
[C言語] コメント文字列を無視...
-
EXCELVBAでSQLserverからデータ...
-
DataGridViewのデータの引渡し...
-
VBA 空白セルを削除ではない方...
-
【エクセル】測定時間がバラバ...
-
メモ帳(テキストデータ)をExc...
-
0が含まれる幾何平均が「#NUM!」
-
Accessで該当データにフラグを...
-
配列でデータが入っている要素...
-
カンマからスラッシュに
-
多量のSUMIF式を軽くしたい
-
<VB>String→Object
-
LoadPictureしたイメージデータ...
-
シリアル通信プログラム(受信...
-
vba ドロップダウンリストの図...
-
ページ数を求めたい
-
ブレーカー落ちで壊れたりしな...
-
ノイズの入った波形をきれいな...
-
クッキーの値のエンコード/デコ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
教えて下さい
-
【エクセル】測定時間がバラバ...
-
多量のSUMIF式を軽くしたい
-
VBA 空白セルを削除ではない方...
-
配列でデータが入っている要素...
-
メモ帳(テキストデータ)をExc...
-
ブレーカー落ちで壊れたりしな...
-
特定のデータの抽出方法を教え...
-
この行は既に別のテーブルに属...
-
EXCELVBAでSQLserverからデータ...
-
CString型の文字列連結について
-
[C言語] コメント文字列を無視...
-
Accessで該当データにフラグを...
-
エクセルで2つの時系列のデー...
-
S9タイプからXタイプにデータ...
-
プログラミング python pandas ...
-
ユーザーフォームのテキストボ...
-
カンマからスラッシュに
-
Excel VBAでのオートフィルター...
-
C# でDataTableの更新を高速化...
おすすめ情報