プロが教えるわが家の防犯対策術!

初歩的な質問で恐縮ですがよろしくお願いいたします。

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の基本仕様を理解していないためと思われます。
ご教示願えれば幸いです。

A 回答 (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 …
引数で指定する時間はもう少し考慮が必要かも知れませんが。
    • good
    • 0
この回答へのお礼

Wr5様

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

他の方法を試みて問題を整理の上再度質問させていただきます。

ありがとうございました。

お礼日時:2011/03/18 17:23

>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回目に~
の間違いです。
    • good
    • 0

>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文挿入により低速化、送信側と同期せず受信バッファが切り捨てられているのではと推察しています。

この二つの困難はどう克服すればいいのでしょうか?。マルチスレッドは殆ど初めて。見当がつきません。
お教え願えれば幸いです。

補足日時:2011/03/17 03:28
    • good
    • 0

自分でこう書いたけど、



> recvSize == sizeof(buf) になってるかは一応見たほうがいいんじゃないかな。完全に挙動が把握できてるならいいけど。

やっぱり send したバイト数 recv されるまで、recv() 繰り返すように書くよな。
かなり頭回らず。
    • good
    • 0

> 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) になってるかは一応見たほうがいいんじゃないかな。完全に挙動が把握できてるならいいけど。
    • good
    • 0
この回答へのお礼

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の仕様をよく確認していませんでした。

ありがとうございました。

お礼日時:2011/03/17 02:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!