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