Help needed: Java Socket and close detection

David M. Lloyd david.lloyd at redhat.com
Wed Jul 13 19:27:18 UTC 2016


I don't think this really makes sense as a place to ask these questions, 
but I can probably answer them to an extent at least.

When a TCP connection is closed normally, the side (we'll call it A) 
which initiates the close (usually by shutting down the write half of 
the socket) sends a FIN and enters into the FIN_WAIT_1 state, and the 
other side (which we'll call B) receives the FIN, entering into the 
CLOSE_WAIT state.

When B receives the FIN, it does two things: it (invisibly) sends an ACK 
to A, and it reports an end-of-file condition on the socket (resulting 
in -1 being read in Java, assuming any other unread data is read).  When 
A receives that ACK, it usually transitions from FIN_WAIT_1 to 
FIN_WAIT_2 (we'll see an exception to that next).

Typically once a -1 is read by B, B will shut down the read half and 
will finish up writing any last bits of data on the socket, and then 
initiate its own close, shutting down the rest of the socket, causing B 
to transition from CLOSE_WAIT to LAST_ACK.  This causes B to send a FIN 
back to A, who then receives it and transitions to TIME_WAIT.  Note that 
if all this happens quickly enough, A might get a FIN+ACK before it gets 
the ACK, causing a direct transition from FIN_WAIT_1 to TIME_WAIT.  If A 
gets the FIN first, it will transition from FIN_WAIT_1 to CLOSING, where 
it will remain until the final ACK comes, at which point it will move to 
TIME_WAIT.  Any transition to CLOSING or TIME_WAIT will cause the "last 
ACK" to be sent, which upon receive will cause B to move to the CLOSED 
state, and allow B to free up the resources associated with the socket. 
  A will remain in TIME_WAIT until a linger timeout expires, at which 
point the socket will be CLOSED and its resources released.

Note that nowhere in this process does an RST come into play.

Now when you close a socket "abruptly", for example by closing the read 
side while the peer is still sending an RST could be generated.  This is 
usually considered a "soft" error condition by the way; you normally 
shouldn't shut things down that way, but it's probably tolerable most of 
the time.  The exception message in this case is generally "Connection 
reset by peer", rather than receiving a graceful -1 as you would in the 
case of receiving a FIN.

There are other ways to force RST to be sent, but most applications 
don't and shouldn't do it.

The tricky bit comes in when you have a connection which is idle on both 
sides.  If both sides are then "closed", that is, both read and write 
halves are shut down at the same time, everything can still happen 
tidily: a FIN is sent, a FIN is received, and we begin the walk towards 
the CLOSED state.  The problem is that if one side doing a whole-channel 
close is not aware that the other side is still sending, an RST will result.

So to answer your questions in order then: first, an RST can be 
generated by the network stack for a variety of reasons, but I would not 
expect well-behaved Java applications to do it normally, unless it's a 
case of application termination or something along those lines.  Second, 
yes it is normal behavior for RST to not be sent.  And third, the JVM 
does detect FIN packets by reporting an EOF to the read side of the 
socket (after the read buffer was fully drained); this represents normal 
application behavior.

PS, if you Google for "TCP state diagram", you will find several ways to 
visualize what I've described above.

On 07/13/2016 10:29 AM, Langer, Christoph wrote:
> Hi folks,
>
> I have a question to the experts - regarding an issue that was reported
> to me by a customer.
>
> In the customer scenario they are running a Servlet engine and the
> Servlet is constantly sending data to a browser client. When the browser
> client is closed, the server does not get a notification of the other
> end having been terminated and is constantly sending out data and
> blocking an application thread. I’m under the assumption that the server
> should get an RST packet from the network upon writing/flushing data to
> the OutputStream as soon as the client is gone and hence an Exception
> should pop up but this isn’t happening.
>
> There is a load balancer and maybe other network infrastructure involved
> in between the Servlet JVM and the browser client. We did some TCPDUMP
> tracing at the load balancer and we could not see an RST packet coming
> in from the client side. But when I’m running the scenario without all
> this network infrastructure involved, e.g. between servers and clients
> in the same network, I would always observe an RST packet once I close
> the browser. A FIN packet is received, too, but this does not lead to an
> Exception and to all my knowledge this can’t be detected, not from the
> java Socket API and even less from the Servlet API which is just dealing
> with Streams.
>
> So my question to the experts is most of all: Would you agree that an
> RST packet should be generated in the network and received by the
> server? Or is it a normal behavior that servers must deal with not
> receiving RSTs and hence needing to wait for a timeout until e.g. the
> load balancer generates an RST? Also, is there any way to detect a FIN
> in the JVM and react on it?
>
> Thanks in advance and best regards
>
> Christoph
>

-- 
- DML


More information about the nio-dev mailing list