简体   繁体   中英

Jetty servlet does not detect that client has disconnected

This is the code of the servlet that I deployed to 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);
    }
  }
}

I then ran on the command line

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

The file A.xml contains about 13,000 lines; so curl correctly displayed each line it received after 1.5 seconds. I then interrupted curl , but to my surprise the servlet continued on running; ie in this while loop.

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

Why does it exhibit this behaviour? I am not using continuations. I am running Jetty 6.1.26. What I want: the servlet thread should stop when it detects that the client has terminated the http connection.

Shouldnt you be expecting IOException, not only InterruptedException ? You would get an IOException when the client disconnects and the server tries to write to it. Isnt it ? (InterruptedException handles the Thread.sleep part, though).

I don't see where you're getting the writer, so I'm assuming it's from response.getWriter().

What I think may be happening is that Jetty buffers the response internally before sending it to the client. It needs to do this because it needs to calculate the response's size so that it may set the "Content-Length" field in the HTTP response header. This is needed by the client so it knows how much to read. (Well, it's not really required but that's another discussion.)

I'm thinking Jetty doesn't actually send the data until you close the writer. I'm also thinking flush() doesn't do anything because it can't send any data until it knows no more is coming. And it isn't checking whether the connection is still active while you are writing to this buffered stream.

Try this for your loop:

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
}

I'm thinking maybe the writer.checkError() propagates up to the actual socket outputstream and checks if it is still open.

Edit 1: Hmmm never mind, I missed the bit where you said that the flush() is sending data to curl. Still, try the checkError() in your loop and let me know if that works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM