views:

167

answers:

3

How can I detect that the client side of a tomcat servlet request has disconnected? I've read that I should do a response.getOutputStream().print(), then a response.getOutputStream().flush() and catch an IOException, but is there a way I can detect this without writing any data?

EDIT:

The servlet sends out a data stream that doesn't necessarily end, but doesn't necessarily have any data flowing through it (it's a stream of real time events). I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera). If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?

A: 

HTTP is stateless, which means that after a client "gets" the data for it's request, the conneciton is closed. There's no open connection to a servlet unless you purposefully send JavaScript to the web browser to download "extra" information that you purposefully don't provide with the servlet. AKA the basis for all AJAX technologies.

Assuming that you are using a AJAX like setup, where the socket is being held open, it is not really possible to know if a socket is valid until you either successfully read from it or write to it. This is because of the standard upon which sockets were implemented. Basically a socket might refer to two different items, the entire connection or the "on my box" side of the connection. The part that you actually interface with maintains an open state until a reason to change the state occurs.

That reason to change the state might be an explicit message from the remote machine, but due to network outages, power outages, machine crashes, or just plain old congestion, an explicit close message can never be guaranteed. That means that until the socket is actually used successfully, you cannot assume that the connection to the remote machine actually is working. You must either read from the socket or write to the socket to know the connection is still valid. Since you cannot typically force a read from the socket (how do you get the other machine to talk to you?) you typically are forced to write to the socket. If the message cannot be delivered, the error will propagate up through the network stack and the socket will close.

So you can check socket state for "was it closed deliberately", but you cannot really know if you have a valid connection without writing something. If it is that critical, use a bit of the AJAX framework to maintain an open socket state (remember we have to defeat normal HTTP handling to keep a socket open anyway) and pump "do nothing" messages down the socket to verify it's connection status.

Perhaps this is on the mark, perhaps it has missed it. More information might guide this answer to a better solution for your needs.

Edwin Buck
'HTTP is stateless, which means that after a client "gets" the data for it's request, the conneciton is closed.'. No it doesn't mean that, and the connection isn't necessarily closed, in fact since HTTP 1.1 it is highly unlikely. 'Stateless' means that all communications are independent request/response pairs.
EJP
@EJP yes, you are right about the HTTP parts, often (if not all of the time) the connection lingers just in case multiple requests need to be made. The protocol dictates that all responses are handled independently, which might means they could be handled in different connections. However, the TCP socket issues are really the underlying reason you must write or read from a socket to know if it is usable. There are a few options for some libraries to have keep alive messages sent for you, but even then the keep alives must be read or written to know if the socket is good.
Edwin Buck
+2  A: 

is there a way I can detect this without writing any data?

No because there isn't a way in TCP/IP to detect it without writing any data.

Don't worry about it. Just complete the request actions and write the response. If the client has disappeared, that will cause an IOException: connection reset, which will be thrown into the servlet container. Nothing you have to do about that.

EJP
*"Nothing you have to do about that."* - and nothing you CAN do about it.
Stephen C
@EJP: I edited the question to clarify. I'd like not to have to send spurious data to the client unless I absolutely have to.
Seth
You won't. You will get an exception instead, and the container will deal with it.
EJP
A: 

I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera).

There the finally block is for. It will be executed regardless of the outcome. E.g.

OutputStream output = null;
try {
    output = response.getOutputStream();
    // ...
    output.flush();
    // ...
} finally {
    // Do your cleanup here.
}

If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?

No, it won't. It just contains the request body which is often already fully in server memory.

BalusC