Windows NIO bug?

Alan Bateman Alan.Bateman at oracle.com
Sun Jul 8 16:04:25 UTC 2018


On 08/07/2018 14:28, Simone Bordet wrote:
> :
> Can you please detail exactly what you mean by "connection
> consistently remain open", because I tried this:
>
> void test(SocketChannel c) {
>    c.close();
>    System.out.println(c.isOpen());
> }
>
> the code above prints false (assume c is non-blocking, registered with
> a selector, etc.) - should it print true instead until the selector is
> woken up?
I mean the underlying socket and connection.

SocketChannel::isOpen will return false because the socket channel is 
closed but this does not reflect the state of the underlying 
socket/connection (at least not when the socket channel is registered 
with one or more Selectors).

If it helps then one way to way to think about this is to assume a 
reference count (it doesn't actually work this way but assume it for 
this discussion). Assume a newly created  SocketChannel starts out with 
a reference count of 1. Calling close decrements the reference count and 
closes the underlying socket/connection if the count goes to zero. 
Assume the reference count is incremented when you register a 
SocketChannel with a Selector and assume it is decremented when its 
cancelled key is flushed from a Selector. Flushing a cancelled key from 
a Selector closes the underlying socket/connection if the reference 
count goes to zero.

Delaying the closing of the underlying socket/connection makes for a 
reliable implementation as it eliminates the complexity and issues that 
go with closing a socket that is potentially being accessed by the 
selector implementations. It also avoids the complexity of dup2 based 
closing that has its own set of issues.

The downside is that it assumes that there are selection operations 
going on. Selectors in a busy server will be continuously waking up due 
to events so closing a socket channel that is registered is okay, it 
will be quickly flushed from the Selector when it wakes up or another 
selection operation is started. If, as happens in your scenario, there 
isn't much going on, then the closing may be delayed a bit and this can 
be puzzling from the perspective of the peer (the client at the other 
end of the connection).

The case where the peer is reading is straight forward. When you a 
socket channel that is registered with one or more Selectors then it is 
the equivalent of decrementing the reference count and also shutting 
down the connection for writing (the equivalent of shutdownOutput). The 
peer reading the connection will read EOF so it won't block indefinitely.

The case where the peer is writing is problematic. The connection is 
half closed but this doesn't prevent the peer from writing bytes and 
potentially blocking when the socket buffers are full. When the 
connection is eventually closed (because the server performs a selector 
operation) then it close the connection that leads to the RST that you 
expect.

Hopefully this you a better understanding of what is going on.

-Alan


More information about the nio-dev mailing list