こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

ソケット通信の受信で、InputStreamの終了が認識出来ません。

ソケット通信の受信で、InputStreamの終了が認識出来ません。

(1)下記のネット上で見つけたチャットクライアントのソース"ChatClient.java"を流用しました。
 http://www.saturn.dti.ne.jp/~npaka/android/SocketEx/index.html
(2000文字を超えるので掲載出来ません)
 チャットサーバもこのサイトのソースを実装しました。この組み合わせで送受信は確認しました。

(2)これに下記のjavaのオープンソースを実装して、バイト読み出しに変更します。
 【"java\io\InputStream.java"より】
  public int read(byte b[]) throws IOException {  //※1
    return read(b, 0, b.length);      //※2
  }

  public int read(byte b[], int off, int len) throws IOException {//※3
    if (b == null) {
      throw new NullPointerException();
    } else if ((off < 0) || (off > b.length) || (len < 0) ||
        ((off + len) > b.length) || ((off + len) < 0)) {
      throw new IndexOutOfBoundsException();
    } else if (len == 0) {
      return 0;
    }

    int c = read();    //※4
    if (c == -1) {
      return -1;
    }
    b[off] = (byte)c;

    int i = 1;
    try {
      for (; i < len ; i++) {
      c = in.read();
      if (c == -1) {
        break;
      }
      if (b != null) {
        b[off + i] = (byte)c;
      }
      }
    } catch (IOException ee) {
    }
    return i;
  }

 ・リンク先のソース中の入力ストリーム読み出し部の名前の付け替え
 size=in.read(w); → size=readsocket(w);

 ・javaのオープンソース"java\io\InputStream.java"中の名前の付け替え
  ※1:public int readsocket(byte b[]) throws IOException {
  ※2:return readsocket2(b, 0, b.length);
  ※3:public int readsocket2(byte b[], int off, int len) throws IOException {
  ※4:int c = in.read();

(3)この変更を行うと、※4の“in.read()”で入力ストリームの終了の"-1"が入って来ず、forループから抜けなくなってしまいました。帰って来るのは送信したコードのみです。どこが悪いのでしょうか?

投稿日時 - 2010-06-24 22:29:04

QNo.5992940

困ってます

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

crossgateです。
レスが遅くなりました。

>1byte以上データがあると、for文の中の※5の箇所で取り込むのですが、
>入力ストリームが無くなっても、終了コード(-1)を返して来ないので、
>次の入力ストリームを待ってしまいfor文から抜けません。

なるほど。
何でバイト読み込みを自分で実装しようとしているかは良くわかりませんが。。。

単にブロックされたくないだけなら、

c = in.read();
if (c == -1) {
  break;
}

ではなくて、

if (in.available() == 0) {
  break;
}
c = in.read();

ならどうでしょう?

投稿日時 - 2010-06-28 19:15:11

お礼

>crossgateさん

ありがとうごさいます。こちらの意図通り動いてくれました。

>何でバイト読み込みを自分で実装しようとしているかは良くわかりませんが。。。

実は、このクライアント側のソケット通信プログラムをandroidに組み込んでいるのですが、その際に、
別のメニュー画面から起動するアクティビティとして実装しています。

このソケット通信画面を抜けてメニュー画面に戻る際に、スレッド起動された受信部はストリーム待ち
なので、そのスレッドが残ったままになってしまい、再度メニューから通信アクティビティを起動すると、
受信スレッドが重なって起動されてしまいました。

そこで100ms程度のタイムアウトで入力待ちを抜けて、スレッドの終了確認をする様に変更したのですが、
元のストリーム入力処理"in.read(w)"だと、データ受信中にタイムアウトとぶつかると、受信データの
配列への展開漏れが起きる恐れが有ったので、バイト単位の読込みに変更しようとして、この問題に
ぶつかりました。


ですが、"in.available()"を使うことで、タイムアウト処理が不必要になったので、元の形に戻して
シンプルなプログラムにする事が出来ました。


"-1"のチェックが使えない理由は何処に有るのか分かれば教えてください。それとも、そもそも
“public int read(byte b[], int off, int len) throws IOException{…}”を使う事が間違っていたのでしょうか?

投稿日時 - 2010-06-29 13:05:37

このQ&Aは役に立ちましたか?

7人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.3

>"-1"のチェックが使えない理由は何処に有るのか分かれば教えてください。それとも、そもそも
>“public int read(byte b[], int off, int len) throws IOException{…}”を使う事が間違っていたのでしょうか?

理由は良く分かりません。

想像ですが、InputStream(もしくはそのサブクラス)のサブクラスをSocket用に作っていて、read()もそこでオーバーライドしているのかと。

つまり、元のソースはInputStream.read()を呼んでいる訳ではなくて、別のXXXXX.read()を呼んでいるんだとすると、read()が「-1」を返すための判定方法も違うだろうし、今回の話しは説明できると思います。

kn0100005さんは java\io\InputStream.java から取って来たんですよね?
java\net 辺りにそんな感じのものが無いかチェックしてみてください。

投稿日時 - 2010-06-29 18:49:34

お礼

>crossgateさん

ありがとうごさいます。


探してみたところ“java\net\SocketInputStream.java”の中に、下記のメソッドが存在しました。

public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}

public int read(byte b[], int off, int length) throws IOException {
int n;

// EOF already encountered
if (eof) {
return -1;
}




}

ご指摘通り、実装するソースを間違えていた様です。

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

投稿日時 - 2010-06-30 12:59:18

ANo.1

※4のread()は入力ストリームの先頭のバイトデータしか読み込んでいないからでは?
1byte以上データがあるとfor文の中にある「if (c == -1) { break; }」でブレークして「i」をreturnするだけのように見えますが。

投稿日時 - 2010-06-24 23:10:11

補足

質問が間違っていたので訂正します。

===============================================================
※4の下のfor文の中の下記の一行ですが、

 c = in.read();      // ※5(←コメント追記)

元々は“c = read(); ”で、実装の際に“c = in.read(); ”と修正した物です。

(3)の文中の"※4"は、"※5"になります。
===============================================================

>crossgateさん

 回答ありがとうございます。


1byte以上データがあると、for文の中の※5の箇所で取り込むのですが、
入力ストリームが無くなっても、終了コード(-1)を返して来ないので、
次の入力ストリームを待ってしまいfor文から抜けません。


宜しくお願いします。

投稿日時 - 2010-06-25 13:09:08

あなたにオススメの質問