【发布时间】:2012-12-10 05:13:17
【问题描述】:
在尝试了几个 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();
}
}
}
在读取 SocketChannel 时,我拔下电缆,Selector.select() 开始旋转并返回 0,现在我没有机会读取或写入频道, 因为主要的读写代码是由if (selectedNum > 0) 守护的,所以现在这是我脑子里冒出来的第一个困惑,从this answer,据说当频道坏了,select() 会返回,而通道的选择键会指示可读/可写,但这里显然不是这样,没有选择键,select() 仍然返回 0。
另外,从EJP's answer 到一个类似的问题:
如果对端关闭套接字:
- 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 套接字会这样,还是我做错了什么?
【问题讨论】:
-
可能是操作系统还没有声明连接断开:您可以重新插入电缆,理论上可以恢复连接。
-
是的,有时当我重新插入电缆时可以恢复连接,有时
select()只是一直返回 0,我不得不手动取消密钥。