いくつかの SO の質問への回答で言及されているさまざまな解決策 ( this、this 、およびその他のいくつか)を試した後、これをエレガントな方法で処理できないことに少し腹を立てていますが、それでもソケットの切断を検出できませんでした (ケーブルを抜いて)。
サーバーの切断を検出する方法が見つからないことを除いて、すべてが完全に機能します。
次のコードがあります。
while (true) {
handlePendingChanges();
int selectedNum = selector.select(3000);
if (selectedNum > 0) {
SelectionKey key = null;
try {
Iterator<SelectionKey> keyIterator = selector.selelctedKeys().iterator();
while (keyIterator.hasNext()) {
key = keyIterator.next();
if (!key.isValid())
continue;
System.out.println("key state: " + key.isReadable() + ", " + key.isWritable());
if (key.isConnectable()) {
finishConnection(key);
} else if (key.isReadable()) {
onRead(key);
} else if (key.isWritable()) {
onWrite(key);
}
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("I am happy that I can catch some errors.");
} finally {
selector.selectedKeys().clear();
}
}
}
SocketChannels が読み取られている間、ケーブルのプラグを抜き、回転を開始して 0 を返します。メインの読み取りと書き込みコードが によって保護されているため、チャネルの読み取りまたは書き込みSelector.select()
を行う機会がありません。これが最初の混乱の原因です。私の頭の中で、この回答から、チャネルが壊れているとselect()が返され、チャネルの選択キーが読み取り可能/書き込み可能を示すと言われていますが、ここでは明らかにそうではなく、キーはありません選択しても 0 を返します。if (selectedNum > 0)
select()
また、同様の質問に対するEJPの回答から:
ピアがソケットを閉じる場合:
- read() は -1 を返します
- readLine() は null を返します
- readXXX() は、その他の X に対して EOFException をスローします。
ここでもそうではありません。コメントアウトして、選択されているかどうかに関係なくすべてのキーを取得するためif (selectedNum > 0)
に使用しようとしましたselector.keys().iterator()
が、それらのキーからの読み取りは -1 を返さず (代わりに 0 が返されます)、それらのキーへの書き込みはEOFException
スローされません。key.isReadable()
キーが選択されていなくてもtrueを返し、falseを返すという1つのことだけに注意しましkey.isWritable()
た(これは、OP_WRITEのキーを登録しなかったためだと思います)。
私の質問は、なぜJavaソケットがこのように動作しているのか、それとも私が何か間違ったことをしたのでしょうか?