1

私は非常に異常な状況に直面しています。HTTP 経由で通信する 2 つの Jboss (7.1) インスタンスがあります。インスタンス A はインスタンス B への HTTP 接続を開き、処理するデータを送信します。接続にはタイムアウトが設定されているため、N 秒後に応答が読み取られない場合、SocketTimeoutEception がスローされます。いくつかのクリーンアップが実行され、接続が閉じられます。インスタンス B にはサーブレットがあり、そのような http リクエストをリッスンし、リクエストが受信されると何らかの計算が行われます。その後、応答が取り込まれ、クライアントに返されます。

問題は、計算に時間がかかりすぎると、クライアント (A) はタイムアウトのために接続を閉じますが、サーバー (B) は通常どおり続行し、しばらくしてから応答を送信しようとすることです。接続が閉じていることを検出してハウスキーピングを行いたいのですが、それができないようです。

HttpServletResponse.flushBuffer() を呼び出してみましたが、例外はスローされません。また、永続的な接続を避けるために、http リクエスト「Connection: close」で明示的に設定しましたが、これは効果がありませんでした。http サーブレットの応答は通常どおり処理され、例外なく void に消えます。何が間違っているのかわかりません。このサイトで次のような他の質問を読みました。

Java の HttpServletResponse には isClientConnected メソッドがありません

Tomcat - サーブレット応答のブロック - フラッシュの問題

しかし、私の場合は機能しません。

jboss サーブレット コンテナーに固有の何かが存在する可能性があり、それが原因で応答が無視またはバッファーされるか、クライアントから閉じようとしても http 接続が再利用される可能性があります (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()

サーバーコード (サーバー 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()
4

1 に答える 1

0

クライアント側で HTTP 接続プールを実行しています。物理接続は実際には閉じられておらず、後で再利用できるようにプールに戻されます。一定のタイムアウトでアイドル状態になると、閉じられてプールから削除されます。そのため、サーバーの flushBuffer() が発生した時点で、接続はまだ有効でした。

また

フラッシュされるデータは、送信側のソケット送信バッファに収まるほど小さかったため、基になる書き込みはすぐに正常に返され、切断は後で非同期的に TCP によって発見されました。

于 2013-01-24T01:20:10.413 に答える