• ベストアンサー

Socket通信プログラム

VisualC++6.0(SDK)を用いてSocket通信(UDP)プログラムを 作成(チャットやメッセンジャーのようなもの)しています。 送信用と受信用 1つのプログラムにて、送受信両方の機能を兼ね備えたものを作成しようと思っています。 で、送信側から送ったデータを受信側で処理(文字列の追加など)をして 受信側から送信側に送り戻したいとおもいます。 送信ボタンにより送信します。受信したデータはエディットボックスに表示します。 が、受信したデータを送り返すとしているために、 いつまでも、受信->送信->受信・・・・を繰り返してしまいます。 これを、正しく動作するようにするには、どのようにしたら良いのでしょうか? ご存知の方宜しくお願い致します。 足りないものがあったら、補足させていただきます。

質問者が選んだベストアンサー

  • ベストアンサー
  • onosuke
  • ベストアンサー率67% (310/456)
回答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を使ったほうがよかったかな?

coolguys
質問者

お礼

大変よく分かりました。 ポインタを取得していたんですか。 ありがとうございました。 少々話は変わるのですが、 ターゲットを見つける(接続が確立されている確認)というのも、 今までのように、返信データを用いて戻ってきたら、接続が確立されている という処理しかないのでしょうか? 繋がっている、繋がっていないということが、わかる方法はないのでしょうか? ご存知でしたら、教えていただけませんでしょうか。

その他の回答 (8)

  • onosuke
  • ベストアンサー率67% (310/456)
回答No.9

UDPだとそうなりますね。 パケットタイプのフィールドを活用すると,いい感じにUDP pingを実装できそう。

coolguys
質問者

お礼

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

  • onosuke
  • ベストアンサー率67% (310/456)
回答No.8

UDP自体が接続(セッション)を確立しない通信ですから,無理です。 必要ならTCPを使いましょう。TCPなら,エラー処理でそういった状態を捕まえられます。

coolguys
質問者

お礼

回答ありがとうございます。 質問がどんどん、逆行しているようで申し訳ないです。 ということは、 試しと言うかで、1回送って返信作業をやって、 戻ってきたら、繋がっているということがある意味 接続確立テストということですね。

  • onosuke
  • ベストアンサー率67% (310/456)
回答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, ...); ... }

coolguys
質問者

お礼

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

  • honiyon
  • ベストアンサー率37% (331/872)
回答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をフラグに使用」という方がシンプルで良いかも知れません(笑  あまり良い回答ではないですが、参考になれば幸いです(.. 

coolguys
質問者

お礼

>構造体の中を連続した領域で確保せよ! やっぱりそういうのがあるんですね。 補足お待ちしております。 使いこなせるかどうかは別ですが・・・(^^j 構造体は連続した値ではないので、 手動にて、連続したデータを自分で作ってしまう。ナルホド。〆(。。) やっぱり、中身は手動でも、データ定義のときに 構造体だとかっこいいですよね。 大変参考になりました。 ありがとうございました。

  • honiyon
  • ベストアンサー率37% (331/872)
回答No.4

こんにちは、honiyonです。  送受信部についての具体例です。  送受信パケットは、Packet構造体に収められているとします。  「~ xxxx ~」は処理の省略です。 /*** 送信ボタンを押された時の処理 ***/  void OnSendButtonClick(){   ////// パケット作成処理   Packet.DataType = true; //初送信を示す。   ~その他メッセージ等をPacketに詰め込む処理~   ////// データ送信処理   ~パケットを相手に送信する~  }  /*** 受信を受けた時の処理 ***/  void OnRecvData(){   ~受信処理を行う~   ////// 初送信データなら返信する   if (Packet.DataType){    Packet.DataType = false; //not 初送信として循環防止!    ~返信処理~   ////// 返信されてきたデータならチェック   } else {    ~チェック処理~   }  }  こんな感じになると思います。  参考になれば幸いです(..

coolguys
質問者

お礼

honiyonさん、回答いただきありがとうございます。 バッチリ b(^^)d 動作できました。 でも、一つだけ分からないことがあったために、 もう一つだけ甘えさせてもらってもよいでしょうか? Packet構造体にデータとフラグを詰め込んだとしますよね。 struct Packet{   bool Type;   char Data[1000]; } とした場合に、送信時のsendtoにてキャストが出来ません。 sendtoの第2引数です。 で、今回は無理やりに文字列の1番目に力技にてフラグを入れたのですが、 構造体の方がスマートなやり方だと思っても出来ませんでした。 大変申し訳ありませんが、よろしくお願いできませんでしょうか?

  • honiyon
  • ベストアンサー率37% (331/872)
回答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/error_control1.htm  ちょっと目的が違うページですが、軽く検索してみたところ、これが一番詳細に説明していましたので(^^;  参考になれば幸いです(..

coolguys
質問者

補足

考え方としては合っているんですね。 TRUEとFALSEの判断が上手くいっていないんで、 何かが違うのかなと思っていたのですが、流れの問題ですか。 流れ図的なものを書いても、コッチが送信で、こっちは受信 受信で送信?と書いているうちに今、どっちの処理をやっていたんだ? と分らなくなってしまって、ぐちゃぐちゃになってしまって分らなくなっていました。 もし良かったら、送信と受信の判断部の処理を簡単にでも良いので、 説明しては戴けませんでしょうか?

  • onosuke
  • ベストアンサー率67% (310/456)
回答No.2

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

coolguys
質問者

補足

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

  • honiyon
  • ベストアンサー率37% (331/872)
回答No.1

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

coolguys
質問者

補足

早速、ありがとうございます。 >本来ならば、どのような動作にしたいのでしょうか? >メッセンジャーのようなもの(1対1での会話)にしたいのであれば、受信したデータは返信せずに画面に表示して終わりにすれば良 >いかと思います。 送信側から、送信ボタンを押すことによって、何度でも送信が行えるようにしたいのです。 通信チェックプログラムのようなものともいえますが、 送ったデータを受信側で持っているデータと比較して正しいか誤っているかを判断したいんです。 私が、やってみたのは、送信データにフラグのようなものを付加して(送信側はONとか) 送信側なら、受信側から送ってきた物に返事は出さない。 というようにしたのですが、一度送信したら2度目は送り返さなくなってしまいました。 受信スレッド:recvfrom -> sendto 送信ボタン・イベント:sendto です。 よろしくお願いします。

関連するQ&A

  • socket通信でのフィルタリング

    linux環境にてC言語でUDPソケットのプログラムを作成しています。 Aの端末からUDPで受信してパケットヘッダの表示及び、宛先アドレスや宛先ポート番号 を書き換えてBの端末にUDPで送信します。 そこで下記の関数を使用して受信しているのですが、パケットキャプチャのように なんでも受信してしまいます。 socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) これを特定のポート番号だけ受信(フィルタ)するにはどのようにすれば良いのでしょうか?

  • UDPを使って通信速度測定プログラムを作成

    java eclipse3.5を使って通信のプログラムを作っています。 TCPの通信速度計測プログラムはWebサイトのソースを参考にして、自分で作りました。 次は、UDPの通信速度計測プログラムを作りたいのです。 TCPでは、送信側で送信データを作成して、受信側で時間を測ります。 データの作成方法と、時間の計測方法は次のようにしています。 送信側: for (int i = 0; i < data - 2; i++) { out.write('X'); } out.write('\\'); out.write('s'); out.flush(); int recvMicroSecond = Integer.parseInt(in.readLine()); System.out.println(data + "バイトを送信するのに" + recvMicroSecond + "マイクロ秒かかる。"); System.out.println(); 送信側で作成したデータ:XXXX…XX\\s 受信側では、最初のXを読み込んだ時点で時間の計測を開始し、sを読み込んだら計測時間をストップして、計測時間を測っています。 UDPでも送信側でこのようなデータをバッファに格納して、 受信側でバッファ内の文字を読み込んで時間の計測を行いたいのですが、 どのクラスの、どのメソッドを使ったらよいか分かりません。 どなたか、よい方法を知りませんか?

    • ベストアンサー
    • Java
  • Javaの断続的なSocket通信について

    Java標準のSocketクラスで通信プログラムを作ろうと思うのですが、インターネットで散見できるサンプルはだいたい単一のデータを送ってそのままプログラムを終わらせてしまうため、繰り返しデータを送る場合のプログラミングの方法がいまいちわかりません。 同一の接続先に断続的にデータを送信する場合は、新しいデータごとにSocketクラスを作り直さないといけないのでしょうか。それとも既存のSocketクラスのメソッドを使ってループ内で送信の待機をさせるのでしょうか。

  • 通信系プログラムについて

    通信のプログラムを組んでいます。tera termでサーバ上で作業を行っています。送信プログラム、受信プログラム、制御プログラム、データ書き込みプログラムと四つのプログラムを同時に実行させるのですが、送受信するデータ量が大きいと、受信プログラムやデータ書き込みプログラムにバス・エラーcore dumpedと表示されます。プログラム中の動的メモリ管理はしっかりやっているつもりですが、考えられる原因はなんでしょうか?一つのサーバで全部のプログラムを動かしているのがまずいんでしょうか?

  • TCP通信のプログラム(java)

    javaを使ってTCP通信のプログラムを作りました。 そのプログラムは次のような動作をさせたいですが、途中までしか動作確認がとれません。 1. 送信側で指定したバイト数のデータを送信する。それにかかった時間を計測する。 2. 送信されたバイトデータを受信する。届いたバイト数の確認をするとともに、受信にかかった時間を計測する。 3. 受信側は1.で行った処理と同じようにして、届いたバイト数分のデータを返信する。 4. 3.で送信側に送信されたデータを受信して、受信時間を計測する。届いたバイト数を確認する。 2.までは、正常に動作します。正常な動作とは、 送信側は、指定した数のバイトデータを送信して、それにかかった時間を計る。 受信側は、送信されたデータを受信して、それにかかった時間を計り、届いたバイト数を確認する。ちなみにこの2つの時間はほぼ同じになります。 ここまではできています。 ですが、送信側が受信側で届いたバイト数分のデータを送信し、送信側でそのデータを受信してその時間を測るというコード(//*受信処理*//という行から下)を追加するとうまくいきません。 受信側では、//*受信処理*//という行から下を追加すると、うまくいきません。 送信と受信処理のコードを載せます。 送信側(送信バイト数は入力させます) Socket sock = new Socket(host, port); BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream()); BufferedInputStream in = new BufferedInputStream(sock.getInputStream()); //*送信処理*// // 送信データを送信する。 int count = 0; // write()の回数 System.out.println("<データ送信処理>"); start = System.nanoTime(); // 計測開始時間 for (int i = 0; i < Data; i++) {   try {     out.write(i);     out.flush();     count++;   } catch (IOException e) {     System.err.println((count + 1) + "つ目のバイト:書き込みエラー");   } } stop = System.nanoTime(); // 計測終了時間 System.out.println("送信完了"); System.out.println("送信されたバイト数:" + count); // 送信スループットを計算する。 // 結果を表示する。 //*受信処理*// // 変数を定義する。 long startNs = 0; // 受信前の時間のナノ秒を返す。 long stopNs = 0; byte[] buf = new byte[1000000]; int total = 0, part; // ストリームの終わりに達し,-1が返されるまで受信する。 System.out.println("<データ受信処理>"); startNs = System.nanoTime(); while ((part = in.read(buf, 0, buf.length)) != -1) {   total += part;   System.out.println(part); } stopNs = System.nanoTime(); System.out.println("受信完了"); System.out.println("受信されたバイト数:" + total); // 受信スループットを計算する。 // 結果を表示する。 // 出力ストリーム・ソケットをクローズする。 out.close(); sock.close(); 受信側のコードは補足欄に載せます。このコードだと、 送信側の計測結果は表示されますが、受信側で受信時間や受信速度などが表示されません。 送信側で通信を強制終了すると、その後に受信側は、結果を表示します。 データを片道ではなく往復させて、それらの処理時間を計測したいのです。うまくいかないのでアドバイスを頂きたいです。 このコードのおかしい部分が分かる方はアドバイスをお願いします。 コードが見にくくて意味がわからないかもしれませんが、そうならば、データを往復させてその時間を測るためのアドバイスをお願いします。

    • ベストアンサー
    • Java
  • socketでのバイナリファイルの扱い方

    javaのsocketを用いてファイルの送信サーバ、受信クライアントを作成しているのですが テストプログラムとしてスレッド化せずに送信・受信部のみ作りました。 症状はバイナリデータの転送がうまくできないことです。ソースを抜粋すると サーバ側で BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());//socketはSocketクラス BufferedInputStream in1 = new BufferedInputStream( new FileInputStream("test1.bmp")); BufferedInputStream in2 = new BufferedInputStream( new FileInputStream("test2.bmp")); while( (c = in1.read() ) != -1 ){   out.write(c); } while( (c = in2.read() ) != -1 ){   out.write(c); } クライアント側で BufferedOutputStream out1 = new BufferedOutputStream( new FileOutputStream("test1.out.bmp") ); BufferedOutputStream out2 = new BufferedOutputStream( new FileOutputStream("test2.out.bmp") ); BufferedInputStream in = new BufferedInputStream( s.getInputStream() ); while( ( c=in.read() ) != -1 ){   out1.write(c); } while( ( c=in.read() ) != -1 ){   out2.write(c); } とやっています。 クライアント側で1回目のin.readを抜けるときにはサーバ側は既に2回のwriteを終わっているようで ファイルはtest1.out.bmpにマージされていました。 サーバ側の1回目のwriteのオブジェクトがcloseしていないことが原因だと思い1回目のwriteが終わった時点でout.close()とした のですがそうやるとsocketも閉じてしまいsocket closeのエラーが生じてしまいました。 このようにならず1本のコネクションでバイナリのデータを複数送信する方法をご存知でしたら教えてください。 [環境] win2ksp1a,j2sdk1.4.1_03,java経験4ヶ月程度

  • c# ソケット非同期通信プログラム

    C#でソケット非同期通信プログラムを作りたいと思い勉強しております。ちなみにソケット通信はc言語ではやっておりました。 今作りたいと思ってるプログラム ・ラジオボタンで接続形態(サーバー・クライアント)を選択。 ・送信ボタンを押した時は送信 ・受信した時は受信データをテキストボックスに表示 ・コネクション数は1つで送受信を行う お手数ではございますが、参考になる様なサイトやアドバイス等があれば宜しくお願い致します。

  • パイプを用いたプロセス間通信について

    VC++2005にて下記サイトを参考にパイプを用いたプロセス間通信を行うプログラムを作成しています。 猫でもわかるプログラミング (1)第242章 匿名パイプ(サーバー側) http://www.kumei.ne.jp/c_lang/sdk3/sdk_242.htm (2)第243章 匿名パイプ(クライアント側) http://www.kumei.ne.jp/c_lang/sdk3/sdk_243.htm サーバー側からWriteFileでデータを送信する際に、 char型配列に入ったバッファデータ「szBuf」を送信し、 クライアント側のReadFileで同じく「szBuf」で受信していますが、 構造体Data ================== typedef TypeData{ int a; int b; char c[10]; }Data; ================== のオブジェクトdataを送信するには、WriteFile及びReadFileの箇所は どのように実装すれば良いのでしょうか? MSDNにはWriteFileの引数の型はLPCVOIDとあるため、 可能だと思うのですが。。。 もし解決策をご存知の方おられましたら、ご教示お願い致します。

  • [winsock]多分レベル低い質問です

    インターネット越しにマシン間でUDPのテストをすべく、 http://www.geekpage.jp/programming/winsock/udp.php の受信プログラムと送信プログラムをまるまるコピーして、その後送信プログラムをちょっといじりました。 まず setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(const char *)&TorF,sizeof(BOOL)); を追加し、 addr.sin_addr.S_un.S_addr = INADDR_BROADCAST; としました。 (TorF変数はBOOL型変数でTRUEで初期化してあります) そして送信プログラムと受信プログラムを別のマシン上に置いて、まず受信プログラムを起動して、送信プログラムを実行しましたが、受信側ではrecv関数待ちが続くだけで、いっこうにデータを受信できません。 備考: ローカルでテストを行ったところ、問題なく受信できました。 ブロードキャストでなく、直接IPを指定してマシン間で送受信をしても、やはりrecv関数でとまってしまいます。 そこで質問ですが、winsockを使用して別のPC間でUDP通信を行う場合、これ以外に設定が必要なのでしょうか。

  • UDPで受信スループットを測定

    Javaを使って通信のプログラムを勉強しています。 UDP通信のスループットを測定するプログラムを作成しています。 送信側で5242880バイトを128回に分割して送信して、 受信側でそれらのパケットを受信する時間を計測するプログラムを 作りたいのですが、受信側でどのタイミングで受信処理を止めるのかがわかりません。 start = System.currentTimeMillis(); for(;;){   socket.receive(RecvPacket);   if(ループを抜ける条件)     break; } stop = System.currentTimeMillis(); で受信し続けて、受信するパケットがなくなったらループを抜けるというように考えました。 UDPでは送信されたパケットがすべて届くという保証はないので、 128回受信したらループを抜けるというようにできないので、困っています。 届いたパケットの数も数えて到達率も計算したいです。 受信が終わったら、ループを抜けるというようにしたいのですが、 どうすればよいでしょうか?

    • ベストアンサー
    • Java