在尝试了几个 SO 问题的答案中提到的不同解决方案( this,this和其他几个)之后,我有点不安,这不能以优雅的方式处理,我仍然无法检测到套接字断开连接(通过拔下电缆)。
我正在使用 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对类似问题的回答:
如果对等方关闭套接字:
- 读取()返回 -1
- readLine() 返回 null
- 对于任何其他 X,readXXX() 抛出 EOFException。
这里也不是这种情况,我尝试注释掉if (selectedNum > 0)
并使用selector.keys().iterator()
来获取所有键,无论它们是否被选中,从这些键中读取不会返回 -1(而是返回 0),并且不会EOFException
抛出对这些键的写入。我只注意到一件事,即使没有选择键,也会key.isReadable()
返回 true 而key.isWritable()
返回 false(我想这可能是因为我没有为 OP_WRITE 注册键)。
我的问题是为什么 Java 套接字的行为是这样的,还是我做错了什么?