
初歩的な質問で恐縮ですがよろしくお願いいたします。
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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# TCP/IP通信時のサーバーからの受信 2 2022/11/23 09:11
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- Visual Basic(VBA) フォルダの場所を可変にしたいです(マクロ) 4 2023/05/11 10:00
- PHP PHPでCookieを使った訪問回数について 1 2023/05/28 14:10
- Excel(エクセル) 2つのVBAを一緒にしたら機能しなくなりました(エクセル) 7 2022/06/02 12:41
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
教えて下さい
-
メモ帳(テキストデータ)をExc...
-
RPGで0が非表示になる。0は0と...
-
wordやexcelでの関数式の求め方
-
ドラゴンクエストのぼうけんの...
-
Accessで該当データにフラグを...
-
VBAでJSONをパースする方法につ...
-
VBA 空白セルを削除ではない方...
-
この行は既に別のテーブルに属...
-
【エクセル】測定時間がバラバ...
-
C# ソケット通信でデータ受信時...
-
2,3度連続して入る同データ...
-
EXCELVBAでSQLserverからデータ...
-
他のプログラムとのデータ転送
-
[Excel] 関数のみでデータの整...
-
C言語を用いて、GNUPLOTでリア...
-
LoadPictureしたイメージデータ...
-
特定のデータの抽出方法を教え...
-
共有メモリへのマッピング(Map...
-
複数の変数にデータがあるかど...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
教えて下さい
-
【エクセル】測定時間がバラバ...
-
多量のSUMIF式を軽くしたい
-
配列でデータが入っている要素...
-
メモ帳(テキストデータ)をExc...
-
ユーザーフォームのテキストボ...
-
特定のデータの抽出方法を教え...
-
二分探索の平均探索回数
-
EXCELVBAでSQLserverからデータ...
-
Accessで該当データにフラグを...
-
VBA 空白セルを削除ではない方...
-
この行は既に別のテーブルに属...
-
Excel VBAでのオートフィルター...
-
[C言語] コメント文字列を無視...
-
エクセルで2つの時系列のデー...
-
アクセス2000で画像データ...
-
CString型の文字列連結について
-
カンマからスラッシュに
-
VBにおいてフォーム間の変数の...
-
<VB>String→Object
おすすめ情報