有一些关于java非阻塞套接字的问题。
如果计时器线程中有5秒钟没有心跳消息,请拔下客户端的lan电缆并关闭客户端的socketchannel。
private void startSendHeartBeatMessage() {
new Timer().scheduleAtFixedRate(new TimerTask() {
@SneakyThrows
@Override
public void run() {
if (connections.size() != 0) {
LocalDateTime now = LocalDateTime.now();
Iterator<MessageClient> iterator = connections.iterator();
while (iterator.hasNext()) {
MessageClient client = iterator.next();
if (client.isClientAlive(now)) {
// got a heartbeat 5 seconds ago
client.setData("heartbeat".getBytes());
SelectionKey key = client.getSocketChannel().keyFor(selector);
key.interestOps(SelectionKey.OP_WRITE); // send heartbeat to client
} else {
// remove client and close socketChannel
log.error("time out");
client.getSocketChannel().close();
iterator.remove();
}
}
}
selector.wakeup();
}
}, 0, 1000);
}
当然,之所以称为channelclose,是因为局域网电缆被拔掉了。
private void startServer() {
executorService.submit(() -> {
try {
while (true) {
if (selector.select(1000) > 0) { // wait for event
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
MessageClient client = (MessageClient) key.attachment();
client.receive(key, selector);
} else if (key.isWritable()) {
MessageClient client = (MessageClient) key.attachment();
client.send(key, selector);
}
}
}
}
} catch (IOException e) {
stopServer();
}
});
startSendHeartBeatMessage();
}
在客户的 socketChannel
关闭计时器 selector.wakeup()
以及 selector.select(1000)
不是唤醒阻塞,也没有捕捉到任何事件 SelectionKey
但是客户端打印出连接和消息传输是成功的。
经过检查,
KQueueSelectorImpl wakeup()
被称为 interruptTriggered
总是 true
当lan插头拔下,插座通道关闭时。
/**
* KQueue based Selector implementation for macOS
*/
class KQueueSelectorImpl extends SelectorImpl {
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
try {
IOUtil.write1(fd1, (byte)0);
} catch (IOException ioe) {
throw new InternalError(ioe);
}
interruptTriggered = true;
}
}
return this;
}
}
不拔下lan电缆,通过cntr+c关闭客户端,可以非常正常地重新连接。
我真的不知道nio的内部工作结构。请帮帮我
执行环境运行在macbook和springboot2上。
谢谢你的阅读。
暂无答案!
目前还没有任何答案,快来回答吧!