• ベストアンサー

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
  • 回答数4
  • ありがとう数5

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

  • ベストアンサー
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.1

ああ、質問番号5470664は結局自力で解決できなかったんですね。 part = in.read(buf); で読んでいるのなら、読み込めたデータの末尾は buf[part-1] です。ここでbufの添字にtotalを使ってはいけません。 もう一つ気をつけなければいけないのはpartの値は0や負になる場合があることです。total += part; を実行する前にpartの値で条件分岐すべきです。

debukawa
質問者

お礼

回答ありがとうございます。 salsberry様のアドバイスのおかげで、sを読み込んだらループを抜けることができました。 しかし、別の問題が生じました。 それは、送信データをすべて読み込まずに受信を終了してしまうという問題です。 私が考えるには、これは、受信側で送信バイトを読み込むときに、 たまたま読み込んだバイト列の最後が115になったからだと考えています。 for(int i = 0; i< total; i++) System.out.println(buf[i]); で読み込んだバイトを一つ一つ見ると、-127~128の文字でした。 この中の115が読み込んだバイトの最後にきてしまったということだと思います。 これを改善するために、送信側で out.write('\\'); out.write('s'); というようにして ‘\\’を読み込んだら読み込み終了の合図をだし、 その後's'を読み込んだら受信終了というようにしたいと考えました。 for(;;){   part = in.read(buf,0,buf.length);   if(part > 0)     total += part;   if(buf[part-2] == '\\'){     on = true;   }else if(on == true && buf[part-1] == 's'){     break;   } } このようにしたら、 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1 というエラーが出ました。これは要素外の配列にアクセスしたことを示すということだと分かりました。 1回目のループでpart=1なら当然part-2は-1なのでエラーが出ると思います。 ですが、このようにして、データの最後から2番目の'\\'を読み込み、 その次に's'を読み込んだら受信終了にしたいのです。 なにかよい方法はあるでしょうか?

その他の回答 (3)

  • perolist
  • ベストアンサー率29% (8/27)
回答No.4

>上のコードでread(buf,int,int)でとどいたバイト数を >確認することは出きるのでしょうか? できるんですけど、たとえば5000Byteのデータを相手が送信して、ネットワークが遅延していたら、途中の2000Byteとかの段階で読み込んじゃいますよ。 かならず、全てのデータが到着している保障がないのです。

debukawa
質問者

お礼

回答ありがとうございます。 その方法を教えていただけないでしょうか?

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.3

>上のコードでread(buf,int,int)でとどいたバイト数を >確認することは出きるのでしょうか? 「上のコード」と三引数のread()の関係が不明です。 引数なしのread()で最初から最後まで読み込むのならバイト数は1ずつ加算すれば良くて、read(byte[],int,int)の出る幕はありません。 もう一つ。 そもそも、どうしてデータの終わりを表す文字(列)が必要なのでしょうか? 送信側がStreamをclose()して、受信側でもうこれ以上読み出せなくなったらそこで終わり、では不十分ですか? 送信側が送ったデータを最後まで受信できたことを確認したいのであれば、「これから何バイト送るよ」というデータを最初にやりとりしておけば簡単です。

debukawa
質問者

お礼

回答ありがとうございます。 >もう一つ。 >そもそも、どうしてデータの終わりを表す文字(列)が必要なのでしょうか? 受信側は受信が終了したら、届いたバイト数分のデータを送信側に送信するようにしたいのです。 ストリームをクローズすると、ソケットもクローズしてしまうということを聞きました。 これでは、受信側がデータを返信することができないと思います。 ですから、データの終わりを示す文字が必要だと考えたのです。 >送信側が送ったデータを最後まで受信できたことを確認したいのであれば、「これから何バイト送るよ」というデータを最初にやりとりしておけば簡単です。 これはデータを送信する前に送信するデータの大きさを示す文字列を送信すればよいのでしょうか? 一つの解決策として、2回の送受信で別のソケットを作成するという方法を考えたのですが、この場合だと、すこし都合が悪いです。 その理由は、最終的には計測のプログラムを2つのホストにセットしたら、ずっと計測をしつづけるようにします。セットしたら後は人間が操作することはできません。 そうすると、何度か計測をした後に、もし指定していたポート番号を他のアプリケーションが使用したら、私のプログラムは通信できなくなってしまいます。 ですから、文字を読み込ませて受信を終了させたいのです。

  • perolist
  • ベストアンサー率29% (8/27)
回答No.2

ByteBuffer っていうクラスがあります。 こんな感じに使います。 http://itpro.nikkeibp.co.jp/article/COLUMN/20060424/236102/ こいつで、ソケットプログラム書いたりできますよ。 positionとか remainingとか使えば、受信したデータ列の任意の場所に移動したり、残りの長さを数えられたりして便利です。 あと、お悩みの件ですが、 ループ中にreadで1文字ずつ読みこんで、そして読み込んだ文字が's'だったら抜けるって書けば済むんじゃないです? //動く自信なし char ch = in.read(); if (ch == 's') { return; } 's'ではなく改行文字'\n'を終端とみなせるようにできるならば String inData = in.readline(); ってお手軽に書けるのにねぇ

debukawa
質問者

お礼

回答ありがとうございます。 以前は提案していただいたコードのようにして受信していたのですが、 受信したバイト数をチェックして、届いたバイト数分のデータを 送信してきたクライアントに返信するという処理をしたいのです。 ですから、読み込んだバイト数を確認する必要があります。 提案していただいたコードで届いたバイト数を確認する方法としては、 1文字読み込んだらCount++するという方法が浮かびました。こんな感じです。 for(;;){ ch = in.read(); Count++; if(ch == '\\'){ on = true; }else if(on == true && (char)ch == 's'){ recv_stop = System.nanoTime(); // 受信後の時間のナノ秒を返す。 System.out.println("受信完了"); break; }else if(on == true && (char)ch != 's'){ on = false; } } 上のコードでread(buf,int,int)でとどいたバイト数を 確認することは出きるのでしょうか?

関連するQ&A

  • read(buf,int,int)メソッドで1文字取得する

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

    • ベストアンサー
    • Java
  • メッセージを受信したら受信終了したい

    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
  • 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
  • readメソッドについて

    初歩的な質問ですが, OutputStream out = socket.getOutputStream(); out.read(); : (何らかの処理が続く) : read()メソッドで送信されたバイトを読み込みますが, 送信側がデータを送信しない間はずっとout.read(); の前でプログラムの動作はストップしているのでしょうか?

    • ベストアンサー
    • 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
  • 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
  • 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メソッドが次の行に処理を渡すタイミング

    C#ですが、Readメソッドを使ってバイト配列を 読み込むとき、次の処理に移るタイミングが よく分かりません(ソケットからデータを受ける時)。 例えば、JAVAなどのreadLine()などは、改行や、 EOFで、次の行に移ります。 Readは、このような、区切りが無いのでよく分かり ません。 0バイトで移るのかとも思いましたが、受信バイト数 を数えると、文字数以上のバイトはいっさい受信 されていないので、送信側で、自動で0バイトを つけているようでもありません。 それでも送信側で文字を送ると、その送信単位で 次の処理に移ってくれています。 送信から次の送信までの区切りは何で認識して いるのでしょうか(区切りがない以上、受信バッファ がいっぱいになるまで、待ってもよさそうですが)。 なにか分かる人がいましたらお願いします。

  • アルゴリズム・ネストループ方式って何?

    プログラムの性能改善の課題が出ているのですが、アルゴリズムとしてネストループ方式、もしくはその延長上のものを用いること、とあります。 図書館でアルゴリズム関係の本を見てみたのですがどこにもネストループに関して説明がなく、大変困っています。 プログラム自体は、ファイルを読み込んで、表示させるだけの簡単なものです。 簡単に抜き出すと、 for (i=0;; i++){ if ((st = read_a(fd_name, &name_buf, i)) <=0) break; for (j = 0;; j++){ if ((st =read_a (fd_home,&home_buf ,j)) <= 0) break; if (!strcmp(name_buf.a , home_buf.b)){ printf("%s =%s (%s)\n", name_buf.a, name_buf.c , home_buf.c); } } if (st <0) break; といったものです。 注意事項として、break文を入れる手法を使わないこととあります。 お願いします。ネストループって何でしょう?教えてください。

  • TCPでパケットロス?

    初めまして。投稿させて頂きます。 現在C/C++でwinsockを使ったプログラミングを行っています。 その中で2台の端末間で画像データのやり取りを行っています。 【開発環境】 OS:Windows Xp sp2,sp3 IDE:VisualStudio2005(2台) TCPを使い、ファイルのバイナリデータを送信して受信し、保存するという単純なプログラムなのですが、受信側で不定期にパケットロス(?)が発生します。以下に簡単なプログラムを示します。 【送信側】 byte szBuf[1025]; int read_fd; _sopen_s(&read_fd,"test.bmp",_O_RDONLY|_O_BINARY,_SH_DENYNO,0); while(true) { rtn=_read(read_fd,szBuf,1024); if(rtn<=0)break; else { snd=send(s,(char*)&szBuf,rtn,0); } } 【受信側】 byte buf[1025]; ofstream os; os.open("test.bmp",ios::binary|ios::out); byte buf[1025]; while(true) { int nRcv = recv(s, (char*)&buf, 1024, 0); if(nRcv<=0) { break; } os.write((char*)buf,nRcv); } os.close(); 何度か実行してみると、受信サイズが送信サイズが少ないことがあり、一回ごとの受信パケットを見てみるとパケットをロスしているような場所(受信サイズが1バイト)があります。 ちなみにデバッグモードの時はあまり起こりませんが、通常実行時は頻繁に発生します。 試しに送信側の snd=send(s,(char*)&szBuf,rtn,0); の後に Sleep(1); と入れてみると、デバッグモードでも通常実行時でも(今のところは)受信の不足がなくなりました。 フィルタリングソフトで細かいことは見ていないのですが、プログラムに問題、あるいは心当たりがある方はご教示願います。

専門家に質問してみよう