简体   繁体   English

超时连接时,HttpServletResponse.flushBuffer()不会引发IOException

[英]HttpServletResponse.flushBuffer() on timed out connection does not throw IOException

I am facing quite an unusual situation. 我面临着非常不寻常的情况。 I have two Jboss (7.1) instances which communicate via HTTP. 我有两个通过HTTP通信的Jboss(7.1)实例。 Instance A opens an HTTP connection to instance B and sends some data to be processed. 实例A打开到实例B的HTTP连接,并发送一些要处理的数据。 The connection has timeout set, so after N seconds if no response is read it throws SocketTimeoutEception. 连接已设置超时,因此在N秒后,如果未读取任何响应,它将引发SocketTimeoutEception。 Some cleanup is performed and the connection is closed. 执行一些清除操作并关闭了连接。 Instance B has a servlet, listening for such http requests and when one is received some computation is done. 实例B有一个servlet,侦听此类http请求,并在收到请求后进行一些计算。 After that the response is populated and returned to the client. 之后,将填充响应并将其返回给客户端。

The problem is that if the computation takes too much time, the client (A) will close the connection due to the time out, but server (B) will proceed as normal and will try to send the response after some time. 问题是,如果计算花费太多时间,则客户端(A)将由于超时而关闭连接,但是服务器(B)将照常进行,并在一段时间后尝试发送响应。 I want to be able to detect that the connection is closed and do some house keeping, however I can't seem to be able to do that. 我希望能够检测到连接已关闭并做一些整理工作,但是我似乎无法做到这一点。

I have tried calling HttpServletResponse.flushBuffer(), but no exception is thrown. 我尝试调用HttpServletResponse.flushBuffer(),但没有引发异常。 I have also explicitly set in the http request "Connection: close" to avoid persistent connection, but this had no effect. 我还已在http请求“连接:关闭”中显式设置以避免持久连接,但这无效。 The http servlet resonse is processed as normal and disappears in the void without any exception. http servlet共振被正常处理,并且消失在空白中,没有任何异常。 I do not know what I am doing wrong, I've read other questions on this site like: 我不知道自己在做什么错,我已经在这个网站上阅读了其他问题,例如:

Java's HttpServletResponse doesn't have isClientConnected method Java的HttpServletResponse没有isClientConnected方法

Tomcat - Servlet response blocking - problems with flush Tomcat-Servlet响应阻止-刷新问题

but they do not work in my case. 但对于我而言,它们不起作用。

I think there might be something specific to the jboss servlet container, which causes to ignore or buffer the response, or perhaps the http connection is reused despite my efforts to close it from the client (A). 我认为jboss servlet容器可能有一些特定的东西,导致忽略或缓冲响应,或者尽管我努力从客户端关闭它,但http连接还是被重用了(A)。 I'd be happy if you could provide some pointers to where to look for the problem. 如果您能提供一些指向哪里寻找问题的指导,我将非常高兴。 I have spend several days on this and no relevant progress was made, so I need to resolve this urgently. 我已经花了几天时间,并且没有取得任何相关进展,因此我需要紧急解决此问题。

Here is the relevant code: 以下是相关代码:

Client code (server A): 客户端代码(服务器A):

    private static int postContent(URL destination, String fileName, InputStream content)
    throws IOException, CRPostException
    {
        HttpURLConnection connection = null;

        //Create the connection object
        connection = (HttpURLConnection)destination.openConnection();

        // Prepare the HTTP headers
        connection.setDoOutput(true);
        connection.setInstanceFollowRedirects(false);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("content-type", "text/xml; charset=UTF-8");
        connection.setRequestProperty("Content-Encoding", "zip");
        connection.setRequestProperty("Connection", "close");//Try to make it non-persistent

        //Timouts
        connection.setConnectTimeout(20000);//20 sec timout
        connection.setReadTimeout(20000);//20 sec read timeout

        // Connect to the remote system
        connection.connect();

        try
        {
            //Write something to the output stream
            writeContent(connection, fileName, content);

            //Handle response from server
            return handleResponse(connection);
        }
        finally
        {
            try
            {
                try
                {
                    connection.getInputStream().close();//Try to explicitly close the connection
                }
                catch (Exception e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                connection.disconnect();//Close the connection??
            }
            catch (Exception e)
            {
                logger.warning("Failed to disconnect the HTTP connection");
            }
        }
    }

private static int handleResponse(HttpURLConnection connection)
    throws IOException, CRPostException
    {
        String responseMessage = connection.getResponseMessage();//Where it blocks until server returns the response 
        int statusCode = connection.getResponseCode();
        if (statusCode == HttpURLConnection.HTTP_OK)
        {
            logger.debug("HTTP status code OK");
            InputStream in = connection.getInputStream();

            try
            {
                if (in != null)
                {
                    //Read the result, parse it and return it
                    ....
                }
            }
            catch (JAXBException e)
            {
            }
        }// if

        //return error state
        return STATE_REJECTED;
    }//handleResponse()

Server code (Server B): 服务器代码(服务器B):

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
{
    String crXML = null;
    MediaType mediaType = null;
    Object result;

    // Get the media type of the received CR XML
    try
    {
        mediaType = getMediaType(request);
        crXML = loadDatatoString(mediaType, request);
        result = apply(crXML);
    }
    catch (Exception e)
    {
        logger.error("Application of uploaded data has failed");

        //Return response that error has occured
        ....

        return;
    }

    // Finally prepare the OK response
    buildStatusResponse(response, result);

    // Try to detect that the connection is broken
    // and the resonse never got to the client
    // and do some housekeeping if so
    try
    {
        response.getOutputStream().flush();
        response.flushBuffer();
    }
    catch (Throwable thr)
    {
        // Exception is never thrown !!!
        // I expect to get an IO exception if the connection has timed out on the client
        // but this never happens
        thr.printStackTrace();
    }
}// doPost(..)

public static void buildStatusResponse(HttpServletResponse responseArg, Object result)
{
    responseArg.setHeader("Connection", "close");//Try to set non persistent connection on the response too - no effect

    responseArg.setStatus(HttpServletResponse.SC_OK);

    // write response object
    ByteArrayOutputStream respBinaryOut = null;
    try
    {
        respBinaryOut = new ByteArrayOutputStream();
        OutputStreamWriter respWriter = new OutputStreamWriter(respBinaryOut, "UTF-8");
        JAXBTools.marshalStatusResponse(result, respWriter);
    }
    catch (Exception e)
    {
        logger.error("Failed to write the response object", e);
        return;
    }

    try
    {
        responseArg.setContentType(ICRConstants.HTTP_CONTENTTYPE_XML_UTF8);
        responseArg.getOutputStream().write(respBinaryOut.toByteArray());
    }
    catch (IOException e)
    {
        logger.error("Failed to write response object in the HTTP response body!", e);
    }
}//buildStatusResponse()

You are running into HTTP connection pooling at the client end. 您正在客户端运行HTTP连接池。 The physical connection isn't really closed, it is returned to a pool for possible later reuse. 物理连接并未真正关闭,而是返回到池中以备后用。 If it is idle for some timeout it is closed and removed from the pool. 如果空闲一段时间后空闲,则将其关闭并从池中删除。 So at the moment the server flushBuffer() happened the connection was still alive. 因此,当服务器flushBuffer()发生时,连接仍然有效。

OR 要么

The data being flushed was small enough to fit into the socket send buffer at the sender, so the underlying write returned immediately and successfully, and the disconnect was only discovered later, asynchronously, by TCP. 刷新的数据足够小,可以放入发送方的套接字发送缓冲区中,因此基础写入立即成功返回,并且断开连接仅在以后由TCP异步发现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 HttpServletResponse#sendError()是否会抛出IOException吗? - Does HttpServletResponse#sendError() ever throw an IOException? “ java.io.IOException:连接超时”和“ SocketTimeoutException:读取超时”之间有什么区别? - What's the difference between “java.io.IOException: Connection timed out” and “SocketTimeoutException: Read timed out” 为什么会抛出 IOException - Why Does It Throw an IOException “java.io.IOException:连接超时”VS HttpTimeoutException 在 java 11 HTTP 客户端上 - “java.io.IOException: Connection timed out” VS HttpTimeoutException On java 11 HTTP Client IOException:无法连接到 /192.168.70.1(端口 9900):连接失败:ETIMEDOUT(连接超时) - IOException: failed to connect to /192.168.70.1 (port 9900): connect failed: ETIMEDOUT (Connection timed out) heroku 连接超时(连接超时) - heroku Connection timed out (Connection timed out) 套接字编程,多线程编程。 错误:IOException:java.net.ConnectException:连接超时:connect - Socket programming, multithreaded programming. Error: IOException: java.net.ConnectException: Connection timed out: connect close是否会抛出IOException? - Does close ever throw an IOException? 为什么HttpServlet抛出IOException? - Why does HttpServlet throw an IOException? 为什么此代码会引发IOException? - Why does this code throw an IOException?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM