如何在servlet规范3中正确检测客户端断开连接?

时间:2011-08-19 16:19:41

标签: java asynchronous client disconnect servlet-3.0

我已尝试写入响应,因为没有正确的断开回调:

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;
    }

}

但这似乎没有诀窍。当客户端断开连接时,写入并刷新缓冲区不会引发异常

奇怪的是,第二次尝试写入输出流时(断开连接后),write会抛出异常。它看起来像你第一次写/刷它,一些内部状态被设置为错误,没有通知。

我已尝试过Jetty 8和Tomcat 7,我也看到了同样的行为。

是否有解决方案可以确定客户是否收到了该消息?我错过了什么吗?

2 个答案:

答案 0 :(得分:1)

我知道您正在寻找一种检测断线的正确方法,但对于那些不介意使用kludge的人:

注意:此方法会在解释结果之前定期向客户端发送必须的空格字符。这是kludgey的一部分。

  1. 启动一个可以访问servlet响应的writer / outputstream的线程。该线程定期向客户端发送空格字符(我使用1秒间隔)。包含IOException try / catch块,用于设置中止标志。

  2. 如果连接已关闭,则当无法将数据传递到客户端时,大多数servlet都会抛出EOFException(这是一个IOException)。您正在捕获此异常并设置中止标志。

  3. 当捕获中止标志时,您有选项。你可以查看正在执行的线程,让你的所有处理周期性地检查中止标志,将异常推送到执行线程,或做任何事情(这里没有详述)。

  4. 如果流程成功完成,您的结果将以多个空格为前缀。再次,请记住在客户端修剪这些内容。

答案 1 :(得分:0)

根据我的经验,当客户端断开与servlet的连接时,会出现一个引用Broken Pipe的异常。

例如:Broken Pipe when writing bytes in ServletOutputStream

我建议捕获java.net.SocketException并查看异常详细信息以验证它是否是一个损坏的管道(作为起点):

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)