Windows NIO bug?
Alan.Bateman at oracle.com
Fri Jul 6 16:51:58 UTC 2018
On 06/07/2018 17:13, Simone Bordet wrote:
> we're hitting a strange behavior that I would like opinion on from this group.
> A client opens a TCP connection to the server and sends a HTTP request
> with a very large body.
> The server accepts the connection, sets interestOps=OP_READ; the
> selector wakes up, sets interestOps=0 and (another thread) goes back
> to select(); the server reads the HTTP request headers only, sends the
> HTTP response _without_ reading the request body, then closes the
> connection via SocketChannel.close().
> After closing the connection there are 2 cases:
> A) the selector is not woken up again
> B) the selector is woken up
> In case A) we see that the client continues to write the request
> content, the server continues to send back TCP ACKs until the TCP
> connection is congested and the client registers for OP_WRITE.
> Unfortunately the server cannot drain the buffers (its connection is
> gone) and so the client stalls.
> In case B) we see that the client continues to write the request
> content, and after a few writes the server responds with a TCP RST.
> Case B) is what always happens on Linux no matter if the selector is
> woken up or not, and I think it's the correct behavior.
> I can easily turn case A) into case B) by adding a bit of code that
> wakes up the selector (just selector.wakeup() is enough).
> It is as if after SocketChannel.close(), in case A), the selector does
> not tell the TCP stack that the socket is gone, so the TCP stack
> continues to ACK even if the SocketChannel is closed and should be
> even "gone" from the OS as well.
> Has anyone seen this?
When you invoke close on a SocketChannel that is registered with one or
more Selectors then the closing of the socket is delayed until it has
been deregistered from all Selectors. This is irrespective of the
interest operation set. With your case A then it sounds like there is no
selection activity so this is why the close is delayed. If the client
were reading then it would read EOF as the implementation does a half
close. There is no graceful equivalent for writing.
More information about the nio-dev