ServerSocketChannelがノンブロッキングモードで使用され、セレクタに登録されている場合、次のchannel.close()コールはソケットをただちに閉じることはなく、netstat出力LISTENING状態です。非ブロックモードのServerSocketChannelが正しく閉じない
単純なテストケースです。
// 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);
}
ServerSocketChannelを正常に閉じることができるのは、セレクタ自体を閉じることです。しかし、セレクタは他のソケットに使用されており、私はそれを閉じたくありません。
セレクタを閉じずにServerSocketChannelを正しく閉じるにはどうすればいいですか?またはそれが閉じられるまで待つ方法?
UPD:Windowsでのみ問題が発生します。解決策が見つけられ、下のコメントに掲載されます。
LISTENING状態にあったポートは、TIME_WAIT状態を決して通過しません。 – EJP
私は、このポートに着信接続がある場合、ソケットがTIME_WAITに登録されていると信じています:http://www.microhowto.info/howto/listen_on_a_tcp_port_with_connections_in_the_time_wait_state.html –
これは以前はESTABLISHED状態だったポートです。両方のポートが同じポート番号を持つので、少し混乱しますが、それが動作する方法です。 – EJP