- PR -

InputStream#read() での例外処理

投稿者投稿内容
ねま
会議室デビュー日: 2004/11/10
投稿数: 18
投稿日時: 2004-11-10 23:51
Socket(実際にはTelnetクライアント)を使用しています。

PC-A(client, win2000) と PC-B(server, linux) とがあり、PC-Aで開発しています。

PC-Aから、InputStream#read() を呼んだとき
 case1. PC-B側の NIC からケーブルを抜くと SocketTimeoutException になります。
 case2. PC-A側の NIC からケーブルを抜くと -1 が返ってきます。

ここで質問です。
質問1:
 この現象はOS に関係なく同じですか?

質問2:
 こういった現象がおきるならば、-1 が返ってきたときは、
 自分で例外を new して返すほうが安全だと思うのですが、皆さんはどうしてますか?

 言い換えると、case1, case2 ともに同じエラー処理をすべきだと思うのですが、
 皆さんはどうされているのでしょうか?

質問3:
 上とは全く関係ない質問ですが、InputStream#read() の Javadoc の質問です。
 下記引用のうち、『ブロックします。』のブロックの意味が分かりません。
 具体的にどういう状態になるのでしょうか?
 メソッドを呼んだ後返ってこないと言う意味でしょうか?

引用:
このメソッドは、入力データが読み込めるようになるか、ストリームの終わりが検出されるか、または例外がスローされるまでブロックします。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-11-11 11:54
質問1:
分かりません。
PC-B側でケーブルを抜いても、PC-A側のOS(上のソケット)はそのようなこ
とを検知することは出来ないと思うので、その場合タイムアウトするまで
read()がブロックしつづける方は、おそらく同じだと思いますが…

質問2:
単にソケットの接続先からのclose要求を受け取った場合も-1が返って
くるはずですので、-1なら須らく例外、というのはまずいですよね。

質問3:
ソケットの入力ストリームバッファや標準入力ストリームバッファには、
"いつデータが書き込まれるか分からない。書き込みを行う側の気分次第。"
という特徴があるのは、お分かりかとおもいます。

InputStream#read()は、ストリームバッファから1バイトを読み取る命令
ですが、もしread()を呼び出した時点でストリームバッファが空の場合は、
そこへの1バイト以上の書き込みが発生するまでずっと"待ち"が発生します。
待っている間は、read()を呼び出したスレッドはずっとその位置で停止した
ままです。この"待っている"状態をブロックしていると呼びます。

ちなみに、"そりゃ困る、読めない状態だったら、直ぐ読み取り処理から抜け
てくれ"という要求にこたえたのが、JDK1.4で加えられたjava.nioのノンブ
ロッキングI/O APIです。
ねま
会議室デビュー日: 2004/11/10
投稿数: 18
投稿日時: 2004-11-11 16:00
シュン様ありがとうございます。

> 質問1:
> 分かりません
ですよね。とりあえず、いろいろな異常系のテストをする前に
経験豊富な有識者の方々にご助言をいただきたかったのです。

> 質問2:
> 単にソケットの接続先からのclose要求を受け取った場合も-1が返って
> くるはずですので、-1なら須らく例外、というのはまずいですよね。

ということは、case1 と case2 とで異なるエラー処理をするほうがよい
という考えなのでしょうか?

補足をすると、client にはGUIが付いています。
それを操作する Actor から見た場合、例外が返ろうが -1 が返ろうが
通信が正常終了でなかったという結果は同じなので、
『通信が切れました』のメッセージで済まそうと考えていました。

なので、-1 が返ったときも例外を生成して、上位の階層で
同じ処理をすればよいのでは、と思ったわけです。

とはいえ、ネットでサンプルを探すと -1 が返ったときに
例外を生成している例はひとつもないんですよね。
だから、-1 が返ったときのエラー処理ってみなさんどうされてるのかな?
と思い投稿したわけです。


> 質問3:
ありがとうございます。よくわかりました。

> ちなみに、"そりゃ困る、読めない状態だったら、直ぐ読み取り処理から抜け
> てくれ"という要求にこたえたのが、JDK1.4で加えられたjava.nioのノンブ
> ロッキングI/O APIです。

java.nio の存在を初めて知りました。利用できるか調査してみます。
自分は、InputStream#available() をread() の前で呼ぶことによって
対応するのかなぁと思ってました。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-11-11 16:23
引用:

なので、-1 が返ったときも例外を生成して、上位の階層で
同じ処理をすればよいのでは、と思ったわけです。


とりあえず、もうちょっと API リファレンスを熟読したほうがいいんじゃないですか。戻り値 -1 はストリームの終端を示しているだけです。異常系ではありませんから例外を放るのはどうかと思います。

とりあえず、IOException を拾っておけばいいと思いますけど。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-11-11 16:56
引用:

ねまさんの書き込み (2004-11-11 16:00) より:

java.nio の存在を初めて知りました。利用できるか調査してみます。




ブロッキングI/Oでは、入力ストリーム毎に1本のスレッドを貼り付け
なければならないので、スケーラビリティにかける、なんとかしろと
言う要求に対する答えです。ですが、無理して使うものじゃないです
よ。スレッドを沢山使って沢山のソケットを監視しているようなサー
バープログラムでは、使うと良いかも、でもプログラムが複雑になる
ので使用はほどほどに。
Telnetプロトコルでの一対一の会話程度なら、必要ないかと思います。

引用:


自分は、InputStream#available() をread() の前で呼ぶことによって
対応するのかなぁと思ってました。




available()から0が返されたとき、ストリーム終端なのか単に今現在たま
たまストリームバッファが空なのかが分からないような…下手をすると永
久ループプログラムが出来てしまうかも。
read()ブロックならストリーム終端で-1を返してくれる("仕様"でそうなって
いる)ので、ストリーム終端に達したことをプログラム側で検知できるので、
そちらを使って判定した方が良いかと思いますよ。
ねま
会議室デビュー日: 2004/11/10
投稿数: 18
投稿日時: 2004-11-11 17:15
未記入様、ありがとうございます。
--------------------------------------------------------
InputStream in;

public String readSample() throws IOException {

StringBuffer sb = new StringBuffer();

while( true ) {
int ch = in.read();
if (ch < 0) {
break;
}
sb.append((char) ch);
}
return sb.toString();
}
--------------------------------------------------------
※このコードは余分な部分は一切省いています。

例えば、上記コードの場合 readSample() の戻り値の正当性は
readSample() の呼び出し元で判断しろ。ということでしょうか?

case2. が発生したとき、readSample() は常に空文字が返ることになりますよね。
私の場合、それはうれしくありません。
(スレッドで毎秒 readSample() を呼んでいるからです。
 裏を返せば、毎秒 server からデータが送られてくることを期待しているからです。)

確かに、case2 以外でも -1 になるケースは、
 case3.ソケットの接続先からのclose要求を受け取った場合
 case4.ストリームの終わりに達して読み込むデータがない場合
と複数あるようです。

ということは、-1 が返ってきたときに、readSample()の呼び出し元で
 state1. -1 だが、readSample() の戻り値が空文字でない場合
     (単純にストリームの終わりに達して、戻り値も正当な場合。)
 state2. -1 かつ、readSample() の戻り値が空文字の場合
 state3. state2.が続く場合。

というような場合わけをした方がよい。ということでしょうか?
今回の場合、少なくとも state3 の状態になったときは
case1. と同じエラー処理をするよう要求されています。
(actor から見て通信できていない状態になるからです)
ねま
会議室デビュー日: 2004/11/10
投稿数: 18
投稿日時: 2004-11-11 17:28
シュン様、ありがとうございます。

java.nio については、もう少し検討してみます。

> available()から0が返されたとき、ストリーム終端なのか単に今現在たま
> たまストリームバッファが空なのかが分からないような…下手をすると永
> 久ループプログラムが出来てしまうかも。

はい。それは承知しています。なので気をつけてプログラミングするのかなぁと。

> read()ブロックならストリーム終端で-1を返してくれる("仕様"でそうなって
> いる)ので、ストリーム終端に達したことをプログラム側で検知できるので、
> そちらを使って判定した方が良いかと思いますよ。

仕様ですか。なるほど勉強になりました。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-11-11 17:42
引用:

 case3.ソケットの接続先からのclose要求を受け取った場合
 case4.ストリームの終わりに達して読み込むデータがない場合


case3. と case4. を分けているのはなぜ? case3. のあとには case4. になるでしょう。

とにかく -1 が返ってくるのはストリーム終端に達したからです。ストリーム終端に達したのが正常にソケットを閉じたからなのかケーブルが抜けたからなのかは知りません。知りたいなら
-1 を受け取ったあとに、Socket#isClosed() でも使って接続状態を確認したらどうですか?

スキルアップ/キャリアアップ(JOB@IT)