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で質問しましょう!
似たような質問が見つかりました
- docomo(ドコモ) +メッセージの送受信。 au(uq mobile)のデータ回線でdocomoの電話番号の+メッセージ 2 2022/09/14 16:09
- HTML・CSS GETをPOSTに変更したところ 送信 不能です。 1 2022/04/10 17:31
- その他(メールソフト・メールサービス) メールサーバーは「PC側がメールをDL済みか否か?」を何を以て感知するのか? 2 2022/12/20 14:56
- その他(メールソフト・メールサービス) サンダーバードでメールが受信されない 10 2022/03/24 17:00
- iPhone(アイフォーン) 皆さんiPhoneは、機能が少な過ぎますか?? iPhoneには、なぜ僕がAndroid合計3台持ち 2 2022/07/12 19:59
- Android(アンドロイド) iPhoneには、なぜ僕が合計3台持ちしているGalaxy A22やXperiaXZ1、arrows 4 2022/07/12 18:42
- Yahoo!メール ぷららメールの送受信が出来なくなった 2 2023/07/16 11:48
- その他(メールソフト・メールサービス) 複数のメールを送信した順と受信した順が違うのは何故? 4 2023/02/22 09:58
- PHP どうして送信されないのでしょうか? 1 2022/12/09 05:23
- C言語・C++・C# TCP/IP通信時のサーバーからの受信 2 2022/11/23 09:11
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
winsockでソケット通信の開発を...
-
「スイッチングハブのバッファ...
-
SerialPortのDataReceivedイベ...
-
VB2005でWin32APIを用いてRS-23...
-
バイナリデータ受信時のデータ順
-
RS232C通信のC言語プログラム:...
-
recv関数の受信結果について
-
誤り制御方式の誤り検出再送要...
-
socket: recvはいつ,どれだけ...
-
UDP処理のエラーについて
-
Macターミナルで実行中のプログ...
-
VBAの配列サイズとメモリに関して
-
緯度、経度の 10進法と 60進法...
-
C言語で、メモリを解放しないで...
-
なんかC言語でプログラム書いて...
-
タスクマネージャーのプロセス...
-
バックグラウンドのプロセスの...
-
TCP/IP通信時のサーバーからの受信
-
プログラミング ソースコード
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
WriteFile()でのデータ送信がで...
-
winsockでソケット通信の開発を...
-
「スイッチングハブのバッファ...
-
socket: recvはいつ,どれだけ...
-
シリアル通信の出力バッファと...
-
Connection reset by peer
-
RS232C通信(PC⇔PLC)
-
RS-232Cでバイナリデータを受信...
-
WaitForMultipleObjects関数の...
-
Linuxでのシリアル通信について...
-
rs232cでの受信データ(mscomm)...
-
UDP処理のエラーについて
-
SocketのSend関数でのCLOSEの検...
-
ソケット通信内 read関数について
-
recv関数の受信結果について
-
シリアルポート通信
-
MSCommでoutputできない
-
SerialPortのDataReceivedイベ...
-
VB2005でWin32APIを用いてRS-23...
おすすめ情報