Сервлет Jetty не обнаруживает, что клиент отключен - PullRequest
5 голосов
/ 04 марта 2011

Это код сервлета, который я развернул на Jetty:

public class StreamServlet extends HttpServlet
{
  public void doGet( HttpServletRequest request, 
    HttpServletResponse response ) throws ServletException, IOException
  {
    response.setContentType( "text/xml; charset=UTF-8" );
    response.setCharacterEncoding( "UTF-8" );

    InputStream is = this.getServletContext().getResourceAsStream( "A.xml" );
    BufferedReader reader = new BufferedReader( 
        new InputStreamReader( is, Charset.forName("UTF-8") ) );

    String line = "";
    try
    {
      while( (line = reader.readLine()) != null ) {
        getServletContext().log( line );
        writer.println( line );
        writer.flush();
        Thread.sleep( 1500 ); // for testing
      }
    }
    catch (InterruptedException e)
    {
        getServletContext().log("exception",e);
    }
  }
}

Затем я запустил в командной строке

curl -i http://localhost:8080/foo/servlet

Файл A.xml содержит около 13 000 строк; поэтому curl правильно отображает каждую строку, полученную через 1,5 секунды. Затем я прервал curl , но, к моему удивлению, сервлет продолжил бежать; т.е. в этом цикле while.

while( (line = reader.readLine()) != null ) {
  getServletContext().log( line );
  writer.println( line );
  writer.flush();
  Thread.sleep( 1500 ); // for testing
}

Почему это проявляет такое поведение? Я не использую продолжения. Я использую Jetty 6.1.26. Что я хочу: поток сервлета должен остановиться, когда он обнаружит, что клиент прервал соединение HTTP.

Ответы [ 2 ]

0 голосов
/ 29 марта 2013

Разве вы не должны ожидать IOException, не только InterruptedException? Вы получите IOException, когда клиент отключается и сервер пытается выполнить запись в него. Не так ли? (InterruptedException обрабатывает часть Thread.sleep, хотя).

0 голосов
/ 29 августа 2011

Я не понимаю, откуда у вас писатель, поэтому я предполагаю, что это из response.getWriter ().

То, что я думаю, может произойти, это то, что Jetty буферизует ответ внутренне перед отправкой его клиенту. Это необходимо сделать, потому что необходимо рассчитать размер ответа, чтобы он мог установить поле «Content-Length» в заголовке ответа HTTP. Это нужно клиенту, чтобы он знал, сколько читать. (Ну, на самом деле это не обязательно, но это другое обсуждение.)

Я думаю, что Джетти на самом деле не отправляет данные, пока вы не закроете писателя. Я также думаю, что flush () ничего не делает, потому что не может отправлять данные, пока не узнает, что больше не будет. И он не проверяет, активно ли соединение, пока вы пишете в этот буферный поток.

Попробуйте это для вашей петли:

for(String line = reader.readLine(); line != null && !writer.checkError(); line = reader.readLine()) {
  getServletContext().log( line );
  writer.println( line );
  writer.flush();
  Thread.sleep( 1500 ); // for testing
}

Я думаю, что возможно writer.checkError () распространяется до фактического выходного потока сокета и проверяет, открыт ли он до сих пор.

Редактировать 1: Хммм, неважно, я пропустил бит, где вы сказали, что flush () отправляет данные в curl. Тем не менее, попробуйте checkError () в вашем цикле и дайте мне знать, если это работает.

...