VisualC++6.0(SDK)を用いてSocket通信(UDP)プログラムを
作成(チャットやメッセンジャーのようなもの)しています。
送信用と受信用
1つのプログラムにて、送受信両方の機能を兼ね備えたものを作成しようと思っています。
で、送信側から送ったデータを受信側で処理(文字列の追加など)をして
受信側から送信側に送り戻したいとおもいます。
送信ボタンにより送信します。受信したデータはエディットボックスに表示します。
が、受信したデータを送り返すとしているために、
いつまでも、受信->送信->受信・・・・を繰り返してしまいます。
これを、正しく動作するようにするには、どのようにしたら良いのでしょうか?
ご存知の方宜しくお願い致します。
足りないものがあったら、補足させていただきます。
No.7ベストアンサー
- 回答日時:
>ラッピング??
>似たような処理で覆い隠す?ということでしょうか。
大体そのような感じです。今回は「送信バッファへの操作を構造体への操作に置換できる」ような送信処理関数を考えています。
下半分の解説ですが,まず,前回のpacket_send()を2箇所訂正させてください。
BOOL packet_send(struct packet *p){
char buf[BUFSIZE];
#define p_type(p) ((u_char *)(p))
#define p_data(p) ( ((char *)p)+1 ) //訂正:型変換がまずかった。
*p_type(buf)=(u_char)p->type; //訂正:ポインタ参照の * が抜けていた。
strncpy(p_data(buf),p->data,DATASIZE);
sendto(..., buf, BUFSIZE, ...);
...
}
このpacket_send()の動作は
1.構造体の内容を送信バッファへとコピーする。
2.作成した送信バッファをsendto()で送信する。
が目的です。(エラー処理は行っていない)
その上で,質問のこの2文ですが,
#define p_type(p) ((u_char *)(p))
#define p_data(p) ( ((char *)p)+1 ) //訂正:型変換がまずかった。
これは,送受信バッファ中で type, data, それぞれの位置(ポインタ)を取得するためのマクロです。目的は,送信/受信時にバッファの処理を共通化すること,後にプロトコルの改変を容易にすること,の2つ。関数に置き換えると
//バッファ中のtypeを示すポインタを取得
u_char *p_type(void *p){ return (u_char *)(p);}
//バッファ中のdataを示すポインタを取得
char *p_data(void *p){ return ( ((char *)p)+1 );}
のようになります。
## 引数にpじゃなく,bufを使ったほうがよかったかな?
大変よく分かりました。
ポインタを取得していたんですか。
ありがとうございました。
少々話は変わるのですが、
ターゲットを見つける(接続が確立されている確認)というのも、
今までのように、返信データを用いて戻ってきたら、接続が確立されている
という処理しかないのでしょうか?
繋がっている、繋がっていないということが、わかる方法はないのでしょうか?
ご存知でしたら、教えていただけませんでしょうか。
No.6
- 回答日時:
> 確か、「構造体の中を連続した領域で確保せよ!」という命令の仕方があった気がするのですが、
packed構造体ですね。
これは,C,C++言語で規定されていないので,それぞれのコンパイラに依存したコードが必要になります。
など偉そうなことをいいながら,私もVC++でのpacked構造体の使い方覚えていません。(^^;; VC++のヘルプを覗いてみてください。
私ならpacked構造体を使わず,このように送信処理をラッピングしてしますね。
#define BUFSIZE 100
#define DATASIZE (BUFSIZE-1)
typedef enum packet_type{
PACKET_SEND=0x01,
PACKET_ACK=0x02
} ptype_t;
struct packet{
ptype_t type;
char data[DATASIZE];
}
BOOL packet_send(struct packet *p){
char buf[BUFSIZE];
#define p_type(p) ((u_char *)(p))
#define p_data(p) ((u_char *)(p+1))
p_type(buf)=(u_char)p->type;
strncpy(p_data(buf),p->data,DATASIZE);
sendto(..., buf, BUFSIZE, ...);
...
}
回答ありがとうございます。
packet構造体、調べてみようと思います。
ラッピング??
似たような処理で覆い隠す?ということでしょうか。見た感じだと。
BOOL packet_send(struct packet *p){
char buf[BUFSIZE];
#define p_type(p) ((u_char *)(p))
#define p_data(p) ((u_char *)(p+1))
p_type(buf)=(u_char)p->type;
strncpy(p_data(buf),p->data,DATASIZE);
sendto(..., buf, BUFSIZE, ...);
...
}
上半分は分かったのですが(単なる定義なので)、
下半分がいまいち理解できません。
特に
#define p_type(p) ((u_char *)(p))
#define p_data(p) ((u_char *)(p+1))
の部分など。
もし宜しかったから、解説してはいただけないでしょうか?
No.5
- 回答日時:
こんにちは、honiyonです。
struct THoge {
char A[2]; //0~2の計3byte
char B[2]; //0~2の計3byte
}
と、THoge構造体を定義すると、メモリ上では、
AAABBB
と連続した 6byteの領域が確保される・・・と思いがちですが、実はそうではないのです。 THoge構造体のなかの、A, B各変数は全く別の場所に確保される事があります。
つまり、 THoge hoge; と宣言して、 @hoge として sendしても、中身を正常に送信出来ないという事になります。
確か、「構造体の中を連続した領域で確保せよ!」という命令の仕方があった気がするのですが、C/C++ではどうやってやるか忘れてしまいました(^^; 識者の方からの補足お待ちします(笑 お願いします(..
では、それ以外の方法での解決策としては、構造体の中身を手動で連続した領域に転送してやる事です。
例えば、
char Data[6]; //0~6 6byte.
と宣言して、
strcpy(@Data[0], hoge.A);
strcpy(@Data[3], hoge.B);
とすれば、Dataの中には、 AAABBB\0 が入りますので、Dataの中の 0~5をsendすればOKです。 構造体の中に文字列以外が含まれる場合は、strcpyではなくmemcpyを使えば良いです。
今回のケースにおいては、構造体の内容は、送受信フラグとメッセージのみのようなので、↑のような面倒な事をするよりは、今行われている通り、「メッセージ中の最初の1byteをフラグに使用」という方がシンプルで良いかも知れません(笑
あまり良い回答ではないですが、参考になれば幸いです(..
>構造体の中を連続した領域で確保せよ!
やっぱりそういうのがあるんですね。
補足お待ちしております。
使いこなせるかどうかは別ですが・・・(^^j
構造体は連続した値ではないので、
手動にて、連続したデータを自分で作ってしまう。ナルホド。〆(。。)
やっぱり、中身は手動でも、データ定義のときに
構造体だとかっこいいですよね。
大変参考になりました。
ありがとうございました。
No.4
- 回答日時:
こんにちは、honiyonです。
送受信部についての具体例です。
送受信パケットは、Packet構造体に収められているとします。
「~ xxxx ~」は処理の省略です。
/*** 送信ボタンを押された時の処理 ***/
void OnSendButtonClick(){
////// パケット作成処理
Packet.DataType = true; //初送信を示す。
~その他メッセージ等をPacketに詰め込む処理~
////// データ送信処理
~パケットを相手に送信する~
}
/*** 受信を受けた時の処理 ***/
void OnRecvData(){
~受信処理を行う~
////// 初送信データなら返信する
if (Packet.DataType){
Packet.DataType = false; //not 初送信として循環防止!
~返信処理~
////// 返信されてきたデータならチェック
} else {
~チェック処理~
}
}
こんな感じになると思います。
参考になれば幸いです(..
honiyonさん、回答いただきありがとうございます。
バッチリ b(^^)d 動作できました。
でも、一つだけ分からないことがあったために、
もう一つだけ甘えさせてもらってもよいでしょうか?
Packet構造体にデータとフラグを詰め込んだとしますよね。
struct Packet{
bool Type;
char Data[1000];
}
とした場合に、送信時のsendtoにてキャストが出来ません。
sendtoの第2引数です。
で、今回は無理やりに文字列の1番目に力技にてフラグを入れたのですが、
構造体の方がスマートなやり方だと思っても出来ませんでした。
大変申し訳ありませんが、よろしくお願いできませんでしょうか?
No.3
- 回答日時:
こんにちは、honiyonです。
そのような仕組みでしたら、送信データに「送信データか。返信データか」を見分けるチェック用フラグをもつ事で対応出来ると思います。
例えば、チェック用フラグを、送信ボタンで送信したデータはtrue, 返信するデータはfalseに設定し、受信側は、trueのデータであれば返信、falseならそのまま。とします。
既にこの仕組みは実践されているようですが、うまくいかないのであれば、それはバグであると思われます。再度コードをチェックしてみましょう。
因みに、データの整合性をチェックする場合、データを返送するという方法ではうまくいかないと思います。返信時にデータが壊れる可能性も考えられるからです。(UDPで壊れる可能性ってあまりないですけどね^^;)
データをチェックしたい場合は、一般に「パリティチェック」と呼ばれる手法が使われます。
簡単に言えば、データを2進数に直し、1の数を数えます。(0でもOK)その合計が、奇数であった場合は、1ビット足して、偶数にします。(その逆でもOK)
そして受信側で、同じように1の数を数え、必ず偶数になるようにそろえているのに、奇数になっていたら、どこかデータが壊れている!と判断できます。
壊れていたら再送を要求するなり何なりで対応します。
詳しく以下のサイトにのっているので参考にしてみてください。
http://www.jtw.zaq.ne.jp/kayakaya/new/kihon/text …
ちょっと目的が違うページですが、軽く検索してみたところ、これが一番詳細に説明していましたので(^^;
参考になれば幸いです(..
この回答への補足
考え方としては合っているんですね。
TRUEとFALSEの判断が上手くいっていないんで、
何かが違うのかなと思っていたのですが、流れの問題ですか。
流れ図的なものを書いても、コッチが送信で、こっちは受信
受信で送信?と書いているうちに今、どっちの処理をやっていたんだ?
と分らなくなってしまって、ぐちゃぐちゃになってしまって分らなくなっていました。
もし良かったら、送信と受信の判断部の処理を簡単にでも良いので、
説明しては戴けませんでしょうか?
No.1
- 回答日時:
こんにちは、honiyonです。
本来ならば、どのような動作にしたいのでしょうか?
メッセンジャーのようなもの(1対1での会話)にしたいのであれば、受信したデータは返信せずに画面に表示して終わりにすれば良いかと思います。
この回答への補足
早速、ありがとうございます。
>本来ならば、どのような動作にしたいのでしょうか?
>メッセンジャーのようなもの(1対1での会話)にしたいのであれば、受信したデータは返信せずに画面に表示して終わりにすれば良
>いかと思います。
送信側から、送信ボタンを押すことによって、何度でも送信が行えるようにしたいのです。
通信チェックプログラムのようなものともいえますが、
送ったデータを受信側で持っているデータと比較して正しいか誤っているかを判断したいんです。
私が、やってみたのは、送信データにフラグのようなものを付加して(送信側はONとか)
送信側なら、受信側から送ってきた物に返事は出さない。
というようにしたのですが、一度送信したら2度目は送り返さなくなってしまいました。
受信スレッド:recvfrom -> sendto
送信ボタン・イベント:sendto
です。
よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
UDP処理のエラーについて
-
【CAsyncSocket::OnReceive()呼...
-
WriteFile()でのデータ送信がで...
-
Macターミナルで実行中のプログ...
-
「ヒープサイズの設定」て何?
-
HTA(HTMLアプリケーション)にて...
-
StrConvの使い方について教えて...
-
ADOでアクセスのレコードに...
-
Arduino nano(アルドゥイーノ ...
-
マイコンからプログラムを読み...
-
C言語 再帰処理のメリットとデ...
-
分を時間に変換するプログラム
-
Excel VBA で処理中断(DoEvents...
-
プログラム実行中に強制終了
-
どうやってパソコンなどの凄い...
-
世界一美しいソースコード
-
iPodの取り外しの際のエラーメ...
-
シャットダウン時のExcel強制終...
-
VBSの処理中一旦処理を止めて再...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
WriteFile()でのデータ送信がで...
-
winsockでソケット通信の開発を...
-
socket: recvはいつ,どれだけ...
-
シリアル通信の出力バッファと...
-
「スイッチングハブのバッファ...
-
SocketのSend関数でのCLOSEの検...
-
Connection reset by peer
-
WaitForMultipleObjects関数の...
-
RS232C通信(PC⇔PLC)
-
VB2005でWin32APIを用いてRS-23...
-
Linuxでのシリアル通信について...
-
UDP処理のエラーについて
-
シリアルポート通信
-
ソケット通信内 read関数について
-
TCP/IP通信プログラミングにお...
-
rs232cでの受信データ(mscomm)...
-
write関数でEAGAINのエラー発生...
-
シリアル通信ができません
-
【CAsyncSocket::OnReceive()呼...
おすすめ情報