Как правильно обнаружить клиентское отключение в сервлете spec 3? - PullRequest
6 голосов
/ 19 августа 2011

Я попытался написать в ответ, потому что нет правильного обратного вызова разъединения:

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

}

Но это не похоже на хитрость. Когда клиент отключен, запись и очистка буфера не привели к исключению .

Странно то, что при второй попытке записи в выходной поток (после отключения) запись вызывает исключение. Похоже, что в первый раз, когда вы пишете / очищаете его, какое-то внутреннее состояние устанавливается на ошибку, без уведомления.

Я пробовал на Jetty 8 и Tomcat 7, и я вижу то же самое поведение.

Есть ли решение, чтобы узнать, получено ли сообщение клиентом? Я что-то пропустил?

Ответы [ 2 ]

1 голос
/ 22 июля 2015

Я понимаю, что вы ищете правильный способ обнаружения разъединений, но для тех, кто не против клуджа:

Примечание. Этот метод периодически отправляет клиенту пробельные символы, которые должны быть обрезаны перед интерпретацией результатов. Это бестолковая часть.

  1. Запустить поток, у которого есть доступ к автору / выходному потоку ответа сервлета. Этот поток периодически отправляет пробелы (я использовал интервалы в 1 секунду) клиенту. Оберните в блок try / catch IOException, который устанавливает ваш флаг прерывания.

  2. Если соединение закрыто, большинство сервлетов генерируют вариант EOFException (который является IOException), когда данные не могут быть доставлены клиенту. Вы перехватываете это исключение и устанавливаете свой флаг прерывания.

  3. Когда флаг отмены пойман, у вас есть варианты. Вы можете обнулить исполняющий поток, периодически выполнять всю проверку на наличие флага отмены, вставить исключение в исполняющий поток или выполнить любое количество действий (здесь не подробно).

  4. В случае успешного завершения процесса вы получите префикс результатов с несколькими пробелами. Опять же, не забудьте обрезать их на своем клиенте.

0 голосов
/ 08 апреля 2013

По моему опыту, когда клиент отключается от сервлета, есть исключение, относящееся к Broken Pipe.

Например: Разбитый канал при записи байтов в 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)
...