7

I have tried writing to the response, because there is no proper disconnect callback:

private boolean write(byte[] output, AsyncContext context) {
    try {
        OutputStream stream  = context.getResponse().getOutputStream();
        stream.write(output);
        stream.flush();
        return true;
    } catch (IOException ex) {
        //client disconnected
        log.error(ex);
        removeAsyncContext(context);
        return false;
    }

}

But this didn't seem to the trick. When the client is disconnected, writing and flushing the buffer did not throw an exception.

The weird thing is, the second time you try to write to the output stream (after the disconnect), the write does throw an exception. It looks like the first time you write/flush it,some internal state is set to error, without notifying.

I have tried on both Jetty 8 and Tomcat 7 and I see the same behavior.

Is there a solution to find out whether the message is received by the client? Am I missing something?

OvdB
  • 121
  • 1
  • 10
  • I noticed that writing two blocks, or after the flush write an extra byte, then flush it again, solves it. Although I find that a bit 'hacky'. – OvdB Aug 23 '11 at 09:29
  • See http://stackoverflow.com/questions/2962196/detecting-client-disconnect-in-tomcat-servlet: TCP/IP doesn't provide means for a callback in case the client disconnected - you'll have to write data. You can create an abstraction over the hackiness though. – Aleksi Yrttiaho Aug 24 '11 at 07:26
  • The problem is that writing data doesn't not throw an exception while the client has disconnected. I found out that writing extra bytes does not always throw an exception. – OvdB Aug 24 '11 at 12:03
  • Also a proper TCP connection termination (FIN & ACK) is not picked up. – OvdB Aug 24 '11 at 12:10

2 Answers2

1

I recognize you are looking for a proper way of detecting disconnects, but for those who don't mind a kludge:

Note: This method periodically sends space characters to the client that must be trimmed before interpreting the results. This is the kludgey part.

  1. Start a thread that has access to the writer/outputstream of the servlet response. This thread sends space characters periodically (I used 1 second intervals) to the client. Wrap in a IOException try/catch block that sets your abort flag.

  2. If the connection is closed, most servlets will throw a flavor of EOFException (which is an IOException) when data cannot be delivered to the client. You are catching this exception and setting your abort flag.

  3. When the abort flag is caught, you have options. You can nuke the executing thread, have all your processing periodically check for the abort flag, push an exception into the executing thread, or do any number of things (not detailed here).

  4. Should the process finish successfully, you will get your results prefixed by a number of spaces. Again, remember to trim these on your client.

Lomilar
  • 64
  • 3
0

In my experience when a client disconnects from a servlet there is an exception referring to a Broken Pipe.

For example: Broken Pipe when writing bytes in ServletOutputStream

I would suggest catching java.net.SocketException and looking at the exception details to verify if it is a broken pipe (as a starting point):

Caused by: ClientAbortException:  java.net.SocketException: Broken pipe
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:358)
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:354)
    at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:381)
    at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:370)
    at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:89)
Community
  • 1
  • 1
Menelaos
  • 23,508
  • 18
  • 90
  • 155