- - PR -
InputStream#read() での例外処理
1|2|3
次のページへ»
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 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-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-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-11-11 16:23
とりあえず、もうちょっと API リファレンスを熟読したほうがいいんじゃないですか。戻り値 -1 はストリームの終端を示しているだけです。異常系ではありませんから例外を放るのはどうかと思います。 とりあえず、IOException を拾っておけばいいと思いますけど。 | ||||||||
|
投稿日時: 2004-11-11 16:56
ブロッキングI/Oでは、入力ストリーム毎に1本のスレッドを貼り付け なければならないので、スケーラビリティにかける、なんとかしろと 言う要求に対する答えです。ですが、無理して使うものじゃないです よ。スレッドを沢山使って沢山のソケットを監視しているようなサー バープログラムでは、使うと良いかも、でもプログラムが複雑になる ので使用はほどほどに。 Telnetプロトコルでの一対一の会話程度なら、必要ないかと思います。
available()から0が返されたとき、ストリーム終端なのか単に今現在たま たまストリームバッファが空なのかが分からないような…下手をすると永 久ループプログラムが出来てしまうかも。 read()ブロックならストリーム終端で-1を返してくれる("仕様"でそうなって いる)ので、ストリーム終端に達したことをプログラム側で検知できるので、 そちらを使って判定した方が良いかと思いますよ。 | ||||||||
|
投稿日時: 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-11 17:28
シュン様、ありがとうございます。
java.nio については、もう少し検討してみます。 > available()から0が返されたとき、ストリーム終端なのか単に今現在たま > たまストリームバッファが空なのかが分からないような…下手をすると永 > 久ループプログラムが出来てしまうかも。 はい。それは承知しています。なので気をつけてプログラミングするのかなぁと。 > read()ブロックならストリーム終端で-1を返してくれる("仕様"でそうなって > いる)ので、ストリーム終端に達したことをプログラム側で検知できるので、 > そちらを使って判定した方が良いかと思いますよ。 仕様ですか。なるほど勉強になりました。 | ||||||||
|
投稿日時: 2004-11-11 17:42
case3. と case4. を分けているのはなぜ? case3. のあとには case4. になるでしょう。 とにかく -1 が返ってくるのはストリーム終端に達したからです。ストリーム終端に達したのが正常にソケットを閉じたからなのかケーブルが抜けたからなのかは知りません。知りたいなら -1 を受け取ったあとに、Socket#isClosed() でも使って接続状態を確認したらどうですか? |
1|2|3
次のページへ»