[英]ServerSocketChannel in non-blocking mode is not closing properly
When ServerSocketChannel is used in non-blocking mode and registered in a selector then the following channel.close() call doesn't immediately closes the socket and it's still visible in netstat output in LISTENING state. 当ServerSocketChannel在非阻塞模式下使用并在选择器中注册时,以下channel.close()调用不会立即关闭套接字,并且在LISTENING状态的netstat输出中仍然可见。
A simple test case. 一个简单的测试用例。
// windows 7 / jdk1.8.0_71 x64
@Test
public void test() throws Exception {
Selector selector = Selector.open();
for (int i = 0; i < 3; i++) {
System.out.printf("Trial %d\n", i);
reopen(selector);
}
}
private void reopen(Selector selector) throws Exception {
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.bind(new InetSocketAddress("127.0.0.1", 17777));
// --- if channel is not registered with selector the following close() method works fine
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_ACCEPT);
// --- trying to cancel the registration in selector - doesn't help
// selectionKey.cancel();
// selector.wakeup();
// --- trying to configure the socket as blocking - doesn't help
// selectionKey.cancel();
// channel.configureBlocking(true);
// --- trying to register the channel in other selector - doesn't help
// selectionKey.cancel();
// Selector nullSelector = Selector.open();
// channel.register(nullSelector, 0);
// nullSelector.close();
channel.close();
// PROBLEM: after close() has returned I still see this port is listening
//
// C:\Dev>netstat -nao | grep 17777
// TCP 127.0.0.1:17777 0.0.0.0:0 LISTENING xxxx
//
// so on the next bind I get an exception: java.net.BindException: Address already in use: bind
// --- it helps!!! but I don't want to because there could multiple server sockets on the same selector
// selector.close();
// --- trying to shake-up the selector - doesn't help
// selector.wakeup();
// --- trying to wait some time - doesn't help
// Thread.sleep(10000);
}
The only chance to close ServerSocketChannel properly is to close the selector itself. 正确关闭ServerSocketChannel的唯一机会是关闭选择器本身。 But the selector is used for other sockets and I don't want to close it. 但是选择器用于其他套接字,我不想关闭它。
How to close ServerSocketChannel properly without closing the selector? 如何在不关闭选择器的情况下正确关闭ServerSocketChannel? Or how to wait until it is being closed? 或者如何等待直到关闭?
UPD: Issue happens on Windows only. UPD:问题仅在Windows上发生。 The solution is found and posted in the comment below. 找到解决方案并将其发布在下面的评论中。
After have tried a lot of options I've found that this code helps: 在尝试了许多选项之后,我发现此代码有帮助:
channel.close();
selector.selectNow();
or 要么
selectionKey.cancel();
selector.selectNow();
channel.close();
but I have no clue why it works. 但我不知道它为什么起作用。 May be someone would explain this. 可能有人会解释这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.