メッセージの受信終了方法についてのアドバイス

このQ&Aのポイント
  • TCPでスループットを測定するプログラムを作成しています。受信終了については、通常はソケットのクローズで行いますが、私のプログラムではデータの受信後に返信を行いたいため、ソケットをクローズすることで受信終了とするのは避けたいです。受信終了の合図として、「finish」というメッセージを送信側から受信側に送る方法を考えています。
  • 送信側では、「finish」というメッセージを送信し、受信側ではread()メソッドでバイト数を確認しながらデータの受信を続けます。受信データのバイト数の最後から6個を確認し、それが「finish」と一致すれば受信終了とします。
  • ただし、受信側での受信終了判定においては、原則としてread()メソッドの戻り値で判定するべきです。受信データに「finish」が含まれる場合でも、read()メソッドの戻り値を確認しながら受信を行うことが推奨されます。このようにすることで、確実な受信終了判定が可能となります。
回答を見る
  • ベストアンサー

メッセージを受信したら受信終了したい

TCPでスループットを測定するプログラムを作っています。 データの受信を終了するには、送信側がソケットをクローズして、 受信側のread()メソッドが-1を返すのが主流だと考えていますが、 私のプログラムでは、受信した後に受信側から送信側へデータを返信したいため、 ソケットをクローズすることで受信終了というようにしたくないです。 また、受信したバイト数をread(buf,int,int)の戻り値で取得したいです。 私が考えている方法としては、送信側で「finish」というメッセージを送信したら、 受信側で受信を終了させようと考えました。 read(buf,int,int)はbufに受信したバイトを格納すると思います。格納されたバイトの最後から6個を確認させ、 finishならば受信終了にすればよいと考えました。 送信側のコードは下のようにしました。 String signal = "finish"; byte[] signal_buf = signal.getBytes(); send_start = System.nanoTime(); for (int i = 0; i < Data-6; i++) {   try {     out.write(i);     out.flush();   } catch (IOException e) {     System.err.println(e);   } } out.write(signal_buf); out.flush(); send_stop = System.nanoTime(); System.out.println("送信完了"); 受信側は、finishを読み込んだらループを抜けるようにしたいです。 recv_start = System.nanoTime(); for(;;){   part = in.read(buf);   if(part > 0)     total += part;   if(finishを読み込んだら){     break;   } } recv_stop = System.nanoTime(); どのようにしてfinishを読み込んだことを認識させれば良いでしょうか? ・合図となるメッセージにより受信を終了すること、 ・read(buf,int,int)の戻り値で読み込んだバイト数を取得すること、 この2点を絶対に削りたくないのです。 どうすればよいか、アドバイスをいただけないでしょうか?

  • Java
  • 回答数2
  • ありがとう数2

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

  • ベストアンサー
回答No.2

UDPは非常に信頼性の低いプロトコルですので、TCPの場合と同様の電文を送受信しても期待したデータを確実に受け取れる保障はありません。 UDPでは、 ・connectに成功しても、相手プロセス(受信側ポート)が存在しているかどうかは不明 ・受信バッファが足りなかった場合に、パケットが破棄されて、エラーかどうかの判別もつかない ・一部パケットをネットワーク上で失っても、分からないことがある のようなことが当然のように発生します。 ですのでUDPでは、(たとえば単なる通知メッセージなどのように)失っても処理に影響を与えないようなもののみを送受信するようにして、 しっかりと送受信したいデータはTCPで送受信するべきだと思います。 性能測定の場合、受信したデータグラムの受信サイズと受信時刻とかをprintするようにして、その時間間隔とサイズを見るぐらいでしょうか。いずれにしても、あまり確実な計測方法は期待しないほうがいいと思います。

debukawa
質問者

お礼

回答ありがとうございます。 送信データをUDPで送信した後、TCPで受信終了させる合図を 送信するという仕組みにしたところ、うまくできました。 アドバイスをしていただき、ありがとうございました。 また、分からないところがあれば質問させていただきますので よろしくお願いします。

その他の回答 (1)

回答No.1

このままだと最後の"finish"が一回のreadで取得されかった場合に、終了の判定ができいことが発生します。 小さいデータサイズであれば、たいてい一回のreadで全部取得できることが多いのですが、しかしその保障はありません。 "finish"を送る直前にflushすると、"finish"は一回で受信できる可能性はそれなりに高まりますが、間にレイヤ3ハブなどが入ったりすると、やはり保障はありません。 アプリケーションレベルの電文形式を決めて、送受信するのが一般的でしょう。 たとえば、 データ電文 = コマンド("DAT") + データ長 + データ 終了電文 = コマンド("FIN") 終了応答電文 = コマンド("ACK") などと決めておいて、 ・送信側 1.データ電文送信 2.終了電文送信 3.コマンド(終了応答電文)のデータサイズ分(例えば3byte)に達するまで繰り返し受信 ・受信側 1.コマンドのデータサイズ分(例えば3byte)に達するまで繰り返し受信 2.データ電文の場合には、 2-1.データ長をデータ長サイズ分(例えば4byte)に達するまで繰り返し受信 2-2.データをデータ長分に達するまで繰り返し受信 3.終了電文の場合には、終了応答電文を送信して、プログラムを終了する というふうにすれば、確実に終了電文を判定できるでしょう。 終了電文での終了か、切断での終了かをprintしておけば、なお確実に確認できます。 また、データ電文を一定サイズに分割送信してみたり、分割サイズを変えてみたりして、性能にどのような影響がでないのか?でるのか?、また、ネットワーク構成をかえるとどうか?、何でそうなるのか?などを探ってみるともっと面白い性能テストができるかもしれませんね。

debukawa
質問者

お礼

回答ありがとうございます。 TCPとUDPのプログラムを作っています。TCPの方はアドバイスをしていただいたおかげで完成しました。 UDPがうまくできません。UDPもおなじようにやればよいのでしょうか?

関連するQ&A

  • read()メソッドを使ったループの抜け方

    通信のプログラムを作っています。 送信側では、指定した数のバイトデータを作成し、送信します。 受信側では、そのバイトデータを受信して、受信にかかった時間を計測します。 送信側では、次のようにしてデータの最後の文字をsとして、作っています。 受信側では、sを読み込んだら、受信完了と見なし、受信処理を終了します。 送信と受信処理のコードを見てください。 送信側(Dataは指定したバイトデータの数値です) for (int i = 0; i < Data-1; i++) {   out.write(i);   out.flush(); } out.write('s'); out.flush(); 受信側 while((part = in.read(buf,0,buf.length)) != -1) {   total += part; } 受信側のコードだと、送信されたバイトがすべて読み込んだらループを抜けるのですが、 そうではなく、sを読み込んだらループを終了させたいのです。 read(buf,int,int)の戻り値を使って受信されたバイト数を確認したいため、 どうしてもread(buf,int,int)を使って受信したいのです。 read(buf,int,int)を使いつつ、送信バイトの最後の文字sを読み込んだら ループを抜けるようにするには、どうすればよいでしょうか? アドバイスをお願いします。 自分で考えたコードを載せます。 読み込んだバイトをbufに入れる。 そして読み込んだバイト数を合計する。 bufの最後の文字がsならループを抜けるというようにしたいのですが、 指定したデータ分を読み込みません。 for(;;){ part = in.read(buf); total += part; if(buf[total] == 's'){ break; } } こちらの方も、指導していただきたいです。

    • ベストアンサー
    • Java
  • 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
  • 出力ストリームへの書き込みでエラー

    サーバ側では、クライアントが送信したバイトデータを受信させます。read()の戻り値を利用して、届いたバイトを確認します。 そして、サーバ側がクライアント側に、届いたバイトデータ分だけの バイトデータを送信します。これらにかかる時間も計測するプログラムを作成しています。 サーバ側がバイトデータを受信し、その時間を計測する所までは、動いたのですが、 サーバ側がクライアント側に、バイトデータを送信する処理の、出力ストリームへの書き込みの処理でエラーが生じます。 Xつ目のバイト:書き込みエラーと表示されます。 なぜエラーになってしまうのでしょうか?送信と受信の処理部分のコードを載せるので、おかしな部分を指摘していただきたいです。 ServerSocket server = new ServerSocket(servPort); Socket sock = server.accept(); BufferedInputStream in = new BufferedInputStream(sock.getInputStream()); BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream()); long startNs = 0; long stopNs = 0; byte[] buf = new byte[1000000]; int total = 0, part; System.out.println("<データ受信処理>"); startNs = System.nanoTime(); // 受信前の時間のナノ秒を返す。 while ((part = in.read(buf)) != -1) { total += part; System.out.println(part); }System.out.println(part); stopNs = System.nanoTime(); // 受信後の時間のナノ秒を返す。 System.out.println("受信完了"); System.out.println("受信されたバイト数:" + total); // 受信スループットを計算する。 ... int count = 0; // write()の回数 System.out.println("<データ送信処理>"); for (int i = 0; i < total; i++) { try { out.write(i); out.flush(); count++; } catch (IOException e) { System.err.println((count + 1) + "つ目のバイト:書き込みエラー"); } } // 結果を表示する。 System.out.println("送信完了"); System.out.println("送信されたバイト数:" + count);

    • ベストアンサー
    • Java
  • UDPプログラム、データの送受信

    javaを使って通信の勉強をしています。 UDPを用いた通信のプログラムを作成しています。 送信側では、次のようにして送信したいバイト数を分割して送信しています。 BUF_MAX = 40960; DatagramSocket socket = new DatagramSocket(); // data分のバイトデータを分割して送信する。 int part = 5242880 / BUF_MAX; // 分割して送信する回数 send_start = System.nanoTime(); for(int i = 0;i < part;i++){   byte[] buf = new byte[BUF_MAX];   buf[0] = (byte)i;   DatagramPacket sendPacket = new DatagramPacket(buf,BUF_MAX,serverAddress,servPort);   total += BUF_MAX;   // 指定したバイト数を送信する。   try{     socket.send(sendPacket);   }catch(IOException e){     System.out.println(e);   } } System.out.println(total); このようにしています。 こうする理由は、5242880バイトのデータを128回に分割して送信して、 受信側で受信したパケットの最初の文字を見て、何個目のパケットが届いていないかを確認するためです。 受信側でこれらのデータを受信する方法を考えているのですが、どうすればよいか分かりません。 receive(packet)で受信するのは知っています。 送信された複数のデータを受信するのに、 for(int i = 0;i < 128; i++){  receive(packet); } というようにするのでしょうか?このようにすると、 このループを抜けることができません。それは、パケットが通信途中で紛失するため、128回受信しないからだとおもいます。 受信しなくなったらループを抜けるというようにすればよいとおもいますが、その方法が分かりません。 どなたかアドバイスをいただけないでしょうか?お願いします。

    • ベストアンサー
    • Java
  • ファイルの受信

    c言語で、クライアント側のファイルを開き、内容をそのまま送信しているはずなのですが上手くいきません。 テキストファイルは正しく送れるようですが、他の実行ファイルなどはダメみたいです。 送信側は、"rb"でオープンし,whileで fread(send_buf,1024,1,fp); send(soc,send_buf,strlen(send_buf),0); を繰り返しています。send_buf[1025]です。 送信側は Recv_buf[1025];で size = recv(soc,Recv_buf,1024,0); fwrite(Recv_buf,size,1,fp); whileで繰り返し受信がなくなったらselectでタイムアウトしています。 いろいろ調べたのですがSleepが必要らしいそうですが・・・どうなんでしょう?

  • 例外処理の付け方

    javaを使って通信のプログラムを作成しています。 ホストAで送信データを作成し、そのデータをホストBに送信して、 ホストAが送信するのにかかった時間と、ホストBが受信するのにかかった時間を 計測するプログラムを作成しました。 送信と受信の処理を行うのですが、送信側では、write()でバッファに書き込んで、 fulsh()で書き込まれたバイトを出力ストリームに書き込みます。 受信側では、while((ch=in.read()) != -1)で送信データをすべて読み込ませます。 write()、fulsh()を使って送信し、read()で受信するのですが、 これらのメソッドが正常に動いたかどうかを調べたいのです。 ネットで方法を調べたのですが、try catchを使うことで例外処理が発生したら、 エラーを出力させることができることがわかりました。 もしurite(),fulsh(),read()が正常に起動しないならエラーを出したいのです。私なりに考えて以下のようにしました。 コードは以下のとおりです。送信部分、受信部分です。 送信側 int count = 0; // write()の回数 System.out.println("<データ送信処理>"); start = System.nanoTime(); // 計測開始時間 for (int i = 0; i < Data - 2; i++) {   try {     out.write(i);     count++;   } catch (IOException e) {     System.out.println(i + ":書き込みエラー");   } } try{   out.write('\\'); }catch(IOException e){   System.out.println("\\" + "書き込みエラー"); } try{   out.write('s'); }catch(IOException e){   System.out.println("s" + "書き込みエラー"); } count = count + 2; out.flush(); stop = System.nanoTime(); // 計測終了時間 System.out.println("送信完了"); 受信側 while (ch != -1) {   try{     ch = in.read();   }catch(IOException e){     System.out.println("読み込みエラー");   }   Count++;   if (ch == '\\') {     on = true;   } else if (on == true && (char) ch == 's') {     stopNs = System.nanoTime();     System.out.println("受信終了時間を確認");     break;   } else if (on == true && (char) ch != 's') {     on = false;   } } メソッドが正常に起動しない場合は、例外処理を行うということを したいのですが、上の方法は正しいのでしょうか? このようにして実行しても、「入力エラー」と言う表示はされません。 もしかしたら、ただ異常な動作が行われていないから、そういったエラーが 表示されないのかもと考えましたが、例外処理の書き方が違う可能性があると思い、 質問させていただきました。 どなたかアドバイスしていただけないでしょうか?

    • ベストアンサー
    • Java
  • java:読み込んだデータの確認

    javaを使って通信のプログラムをつくっています。 送信側でバイトデータを作成して送信します。そして受信側でそのバイトデータを読み込みます。 送信側で作ったバイト数が本当に受信側に届いたかのチェックをするには、 どうすればよいでしょうか?下のコードは、自作した受信処理です。 調べると、read(byte[] b,int off,int len)の返り値が読み込んだバイト数ということなので、 これを使うのではないかと思うのですが、どう使えばよいか分かりません。下のコードは、とりあえず、受信したらcount++として受信処理分だけ countを増やして受信したバイトを数えています。 readの返り値で受信したバイト数を取得するには、どうすればよいでしょうか? 御教授お願いします。 送信側 BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream()); for (int i = 0; i < Data; i++) {   for (;;) {     try {       out.write(i);       out.flush();       count++;       break;     } catch (IOException e) {       System.err.println((count + 1) + "つ目のバイト:書き込みエラー>>再書き込み");     }   } } 受信側 BufferedInputStream in = new BufferedInputStream(sock.getInputStream()); int ch = 0; // 読み込んだ文字 int Count = 0; // 届いたバイト数のカウンター while (ch != -1) {   try {     ch = in.read(); Count++;   } catch (IOException e) {     System.err.println(Count + "つ目のバイトデータ:読み込みエラー");   } }

    • ベストアンサー
    • Java
  • read(buf,int,int)メソッドで1文字取得する

    javaを使ってプログラミングを勉強しています。 read(buf,int,int)メソッドで受信したバイトデータをbufに格納していると思うのですが、 格納したバイトの最後の文字を取得する方法が分かりません。 送信側では送信バイトの最後の文字をsにして送信します。 受信側では読み込んだバイトデータの最後の文字がsだったら、 ループを抜けるというようにしたいのです。 どうやって最後の文字を取得するのでしょうか?

    • ベストアンサー
    • Java
  • 受信処理の終了条件

    TCP通信でデータを送受信してスループットを測定するプログラムを作成しました。 1.ホストAがデータを送信し,ホストBがそれを受信し、スループットを計算する. 2.ホストBがデータを送信し,ホストAがそれを受信し,スループットを計算する. 3.ホストAがホストBにfinishという文字列を送信する. 4.ホストBがホストAにfinish_recvを送信する. 5.プログラムを終了する. 1と2を行った後,測定終了しましたという意味のfinishをホストAからホストBに送信させます。 ホストAの動作が何らかのアクシデントで2.の途中、つまり受信処理中に止まってしまった場合, ホストBはfinishを受信するためにずっと受信状態で待つことになるとおもうのですが, ホストAは止まっているので,finishが受信されずに永遠に受信待機になると思います. このように何らかのアクシデントで受信処理が終わらなくなった場合、受信しなくても 強制的に受信処理を終わらせることはできますか? 私が考えたのは時間内にデータが送信されてこなかったら強制的に受信を止めさせるというものです. なにかよい方法はありませんか?アドバイスをしていただきたいです.

    • ベストアンサー
    • Java
  • ソケットプログラミングについて

    こんにちは。 以前、この掲示板に質問させていただいた者です。 送信側から受信側へWinsockを利用し、jpeg,mpegファイルを送信したいのですが、プログラムを実行すると強制終了されてしまいます。以下に主要部分を記述します。 [送信側] FILE *fp; char fname[100]; printf("読み込み用ファイルを入力して下さい:"); scanf("%s",fname); if((fp = fopen(fname,"rb")) == NULL){ printf("入力ファイルをオープンできない。\n"); exit(1); } char send_buf[1025]; int nRet; int n; while(n = fread(send_buf,1,1024,fp) != -1){ sendto(theSocket,send_buf,n,0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr)); } fclose(fp); closesocket(theSocket); [受信側] FILE *fp; char fname[100]; printf("書き込み用ファイルを入力して下さい:"); scanf("%s",fname); if((fp = fopen(fname,"wb")) == NULL){ printf("出力ファイルをオープンできない。\n"); exit(1); } char Recv_buf[1025]; char size; SOCKADDR_IN saClient; while(1){ size = recvfrom(theSocket,Recv_buf,1024,0,(LPSOCKADDR)&saClient,&nLen); fwrite(Recv_buf,size,1,fp); } fclose(fp); closesocket(theSocket); 受信側を先に起動し、送信側を起動。送信側で1024バイトずつ送信し、受信側でwhileの無限ループを用いて送信側からのデータを受信するプログラムにしたつもりです。しかし、送信側で読み込みファイルを指定すると強制終了されてしまいます。ファイルオープンの仕方がおかしいのでしょうか?また、上記のプログラムでは1024バイトずつ送信できるようになっていますでしょうか? よろしくお願いします。

専門家に質問してみよう