简体   繁体   中英

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.

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. 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? Or how to wait until it is being closed?

UPD: Issue happens on Windows only. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM