Я расстроен тем, что это невозможно обработать элегантным способом, попробовав разные решения (this, this и несколько других), упомянутых в ответах на несколько вопросов SO, я до сих пор не смог обнаружить разъединение разъемов (отсоединив кабель).
Я использую неблокирующий сокет NIO, все работает отлично, за исключением того, что я не нашел способа обнаружить отключение сервера.
У меня есть следующий код:
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, я отсоединяю кабель, а Selector.select()
начинает вращаться и возвращается 0, теперь у меня нет возможности читать или писать каналы, потому что основной код чтения и записи защищен if (selectedNum > 0)
, теперь это первая путаница, исходящая из моей головы, от этого ответа, говорится, что когда канал будет разбит, select() вернется, а клавиша выбора канала будет отображаться как читаемая/записываемая, но, по-видимому, это не так, ключи не выбраны, select()
все еще возвращает 0.
Кроме того, из ответа EJP на аналогичный вопрос:
Если сверстник закрывает сокет:
- read() возвращает -1
- readLine() возвращает null
- readXXX() выдает исключение EOFException для любого другого X.
В этом случае я не пробовал комментировать if (selectedNum > 0)
и использовать selector.keys().iterator()
, чтобы получить все ключи независимо от того, выбраны они или нет, чтение из этих ключей не возвращает -1 (вместо этого возвращено 0) и запись на эти клавиши не получает EOFException
. Я заметил только одно: даже клавиши не выбраны, key.isReadable()
возвращает true, а key.isWritable()
возвращает false (думаю, это может быть потому, что я не зарегистрировал ключи для OP_WRITE).
Мой вопрос: почему Java-сокет ведет себя так или есть что-то, что я сделал неправильно?