アプリ版:「スタンプのみでお礼する」機能のリリースについて

VisualC++6.0(SDK)を用いてSocket通信(UDP)プログラムを
作成(チャットやメッセンジャーのようなもの)しています。

送信用と受信用
1つのプログラムにて、送受信両方の機能を兼ね備えたものを作成しようと思っています。

で、送信側から送ったデータを受信側で処理(文字列の追加など)をして
受信側から送信側に送り戻したいとおもいます。
送信ボタンにより送信します。受信したデータはエディットボックスに表示します。

が、受信したデータを送り返すとしているために、
いつまでも、受信->送信->受信・・・・を繰り返してしまいます。

これを、正しく動作するようにするには、どのようにしたら良いのでしょうか?
ご存知の方宜しくお願い致します。
足りないものがあったら、補足させていただきます。

A 回答 (9件)

>ラッピング??


>似たような処理で覆い隠す?ということでしょうか。

大体そのような感じです。今回は「送信バッファへの操作を構造体への操作に置換できる」ような送信処理関数を考えています。

下半分の解説ですが,まず,前回の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を使ったほうがよかったかな?
    • good
    • 0
この回答へのお礼

大変よく分かりました。
ポインタを取得していたんですか。

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


少々話は変わるのですが、
ターゲットを見つける(接続が確立されている確認)というのも、
今までのように、返信データを用いて戻ってきたら、接続が確立されている
という処理しかないのでしょうか?
繋がっている、繋がっていないということが、わかる方法はないのでしょうか?

ご存知でしたら、教えていただけませんでしょうか。

お礼日時:2002/04/15 17:01

UDPだとそうなりますね。

パケットタイプのフィールドを活用すると,いい感じにUDP pingを実装できそう。
    • good
    • 0
この回答へのお礼

遅くなりましたが、
なんとか、なりました。

大変ありがとう御座いました。
また、質問したときは、よろしくお願いします。

お礼日時:2002/05/07 16:19

UDP自体が接続(セッション)を確立しない通信ですから,無理です。


必要ならTCPを使いましょう。TCPなら,エラー処理でそういった状態を捕まえられます。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
質問がどんどん、逆行しているようで申し訳ないです。

ということは、
試しと言うかで、1回送って返信作業をやって、
戻ってきたら、繋がっているということがある意味
接続確立テストということですね。

お礼日時:2002/04/16 10:04

> 確か、「構造体の中を連続した領域で確保せよ!」という命令の仕方があった気がするのですが、



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, ...);
...
}
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
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))
の部分など。
もし宜しかったから、解説してはいただけないでしょうか?

お礼日時:2002/04/05 10:18

 こんにちは、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をフラグに使用」という方がシンプルで良いかも知れません(笑

 あまり良い回答ではないですが、参考になれば幸いです(.. 
    • good
    • 0
この回答へのお礼

>構造体の中を連続した領域で確保せよ!

やっぱりそういうのがあるんですね。
補足お待ちしております。
使いこなせるかどうかは別ですが・・・(^^j

構造体は連続した値ではないので、
手動にて、連続したデータを自分で作ってしまう。ナルホド。〆(。。)

やっぱり、中身は手動でも、データ定義のときに
構造体だとかっこいいですよね。

大変参考になりました。
ありがとうございました。

お礼日時:2002/04/04 15:36

こんにちは、honiyonです。



 送受信部についての具体例です。
 送受信パケットは、Packet構造体に収められているとします。
 「~ xxxx ~」は処理の省略です。

/*** 送信ボタンを押された時の処理 ***/
 void OnSendButtonClick(){
  ////// パケット作成処理
  Packet.DataType = true; //初送信を示す。
  ~その他メッセージ等をPacketに詰め込む処理~

  ////// データ送信処理
  ~パケットを相手に送信する~
 }

 /*** 受信を受けた時の処理 ***/
 void OnRecvData(){
  ~受信処理を行う~
  ////// 初送信データなら返信する
  if (Packet.DataType){
   Packet.DataType = false; //not 初送信として循環防止!
   ~返信処理~

  ////// 返信されてきたデータならチェック
  } else {
   ~チェック処理~
  }
 }

 こんな感じになると思います。
 参考になれば幸いです(..
    • good
    • 0
この回答へのお礼

honiyonさん、回答いただきありがとうございます。

バッチリ b(^^)d 動作できました。

でも、一つだけ分からないことがあったために、
もう一つだけ甘えさせてもらってもよいでしょうか?

Packet構造体にデータとフラグを詰め込んだとしますよね。
struct Packet{
  bool Type;
  char Data[1000];
}

とした場合に、送信時のsendtoにてキャストが出来ません。
sendtoの第2引数です。

で、今回は無理やりに文字列の1番目に力技にてフラグを入れたのですが、
構造体の方がスマートなやり方だと思っても出来ませんでした。

大変申し訳ありませんが、よろしくお願いできませんでしょうか?

お礼日時:2002/04/02 15:41

こんにちは、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の判断が上手くいっていないんで、
何かが違うのかなと思っていたのですが、流れの問題ですか。
流れ図的なものを書いても、コッチが送信で、こっちは受信
受信で送信?と書いているうちに今、どっちの処理をやっていたんだ?
と分らなくなってしまって、ぐちゃぐちゃになってしまって分らなくなっていました。

もし良かったら、送信と受信の判断部の処理を簡単にでも良いので、
説明しては戴けませんでしょうか?

補足日時:2002/03/31 06:46
    • good
    • 0

デバッガを使う,printf()デバッグを行う,などしてプログラム内部での処理の流れを確認してみては?

この回答への補足

デバッカは当然使っていますし、
TRACE0なども用いています。
そのほかの使い方ということでしょうか?
詳細にお願いできませんか?
どこの流れを確認したら良いのでしょうか?

補足日時:2002/03/31 06:38
    • good
    • 0

こんにちは、honiyonです。



 本来ならば、どのような動作にしたいのでしょうか?

 メッセンジャーのようなもの(1対1での会話)にしたいのであれば、受信したデータは返信せずに画面に表示して終わりにすれば良いかと思います。

この回答への補足

早速、ありがとうございます。

>本来ならば、どのような動作にしたいのでしょうか?
>メッセンジャーのようなもの(1対1での会話)にしたいのであれば、受信したデータは返信せずに画面に表示して終わりにすれば良
>いかと思います。
送信側から、送信ボタンを押すことによって、何度でも送信が行えるようにしたいのです。
通信チェックプログラムのようなものともいえますが、
送ったデータを受信側で持っているデータと比較して正しいか誤っているかを判断したいんです。

私が、やってみたのは、送信データにフラグのようなものを付加して(送信側はONとか)
送信側なら、受信側から送ってきた物に返事は出さない。
というようにしたのですが、一度送信したら2度目は送り返さなくなってしまいました。
受信スレッド:recvfrom -> sendto
送信ボタン・イベント:sendto
です。

よろしくお願いします。

補足日時:2002/03/29 17:52
    • good
    • 0

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