I have a problem with my java application related to HTTP communication.

Application description:

1.      Client – server. Server is running in servlet container. We use Tomcat.

Client use java HTTP library to communicate with the server.

2.      When client establish connection to the server it sends GET request 
(keepalive) and server creates AsyncContext for the client with 10 days timeout.

3.      After connection established server periodically sends data to the 
client using AsyncContext and on the client side there is special thread which 
reads and processes the data.

Client reading thread example:

private class GetRunnable implements Runnable {

       private final HttpURLConnection httpConn;
       private final MyConnection myConn;

       public GetRunnable(final MyConnection myConn) throws IOException, 
AppException {
             this.myConn = myConn;
             final String jSession = myConn.getJSession();
             httpConn = openHttpUrlConnection(false, httpPostTimeout, jSession);
             httpConn.connect();
             final int respCode = httpConn.getResponseCode();
             if (respCode != HttpURLConnection.HTTP_OK) {
                    String info = "Incorrect response from server, 
responseCode:" + respCode + ", message:" + httpConn.getResponseMessage();
                    log.error(info);
                    throw new AppException(info);
             } else {
                    log.trace("GET connected");
             }
       }

       @Override
       public void run() {
             try (final BufferedReader reader = new BufferedReader(new 
InputStreamReader(httpConn.getInputStream(), "UTF-8")) ) {
                    log.info("doGet STARTED");
                    final Thread t = Thread.currentThread();
                    while (!t.isInterrupted()) {
                           log.trace("before readline");
                           final String line = reader.readLine();
                           log.trace("after readline: [" + line + "]");

                           //INFO: DATA PROCESSING HERE
                    }
             } catch (IOException e) {
                    log.error("Error while doGet");
             } catch (Throwable e) {
                    log.debug("doGet STOPED...");
                    log.error("Error while read input msg, do logoff", e);
                    logoff();
                    throw e;
             }
             log.debug("doGet STOPED...");
             myCallback.onGetClose(myConn, connInfo);
       }
}

Server side code to push data looks like this:

protected int sendMsgs(final MyConnection myConn, final String info) {

       int res;
       try {
             final AsyncContext lAc = _ac;
             final ServletRequest req = lAc.getRequest();
             if (!req.isAsyncStarted()) {
                    log.debug("AsyncStarted=false on begin, uid:" + uid + ", 
sid:" + sid);
                    return -1;
             }

             final ServletResponse res = lAc.getResponse();
             ServletOutputStream  os = null;
             final String text = getData(myConn);

             if (os == null)
                    os = res.getOutputStream();

             write2stream(os, text, 0x4000);
             os.println();

             if (os != null)
                    os.flush();
        } catch(IOException ex) {
             log.error("Notify failed");
        } catch (InterruptedException e) {
             log.error("Notify failed");
             Thread.currentThread().interrupt();
             } catch (Throwable e) {
                    log.error("Notify failed");
                    logoff(true);
             }

        return res;
    }

public static void write2stream(final OutputStream outputStream, final String 
text, int bufferSize) throws IOException {
             final CharsetEncoder encoder = 
getHttpEncodingCharset().newEncoder();

             final int fullLen = text.length();
             final int byteBufferSize = Math.min(bufferSize, fullLen);

             final int en = (int)(byteBufferSize * 
(double)encoder.maxBytesPerChar());
             final byte[] byteArray = new byte[en];

              final ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
              final CharBuffer charBuffer = CharBuffer.wrap(text);
             for(int pos=0, len=byteBufferSize;
                           pos < fullLen;
                           pos=len, len=Math.min(pos+byteBufferSize, fullLen)) {

              try {
                final CharBuffer window = charBuffer.subSequence(pos, len);

                           CoderResult res = encoder.encode(window, byteBuffer, 
true);

                if (!res.isUnderflow())
                    res.throwException();

                res = encoder.flush(byteBuffer);

                if (!res.isUnderflow())
                    res.throwException();

            } catch (final CharacterCodingException x) {
                throw new Error(x);
            }

            outputStream.write(byteArray, 0, byteBuffer.position());

            byteBuffer.clear();
            encoder.reset();
             }
       }

Usually this code works fine but it there is no data from server to client for 
1 day and after 24 hours (can be 16 or 12) data appears, server cannot send 
data to the client.
In the log there is no error. It is written that everything flushed but client 
still waiting for data in “final String line = reader.readLine();”
When 2nd portion of data is sent by the server, then during flush I see the 
following error

2016-01-26 00:00:00,051|INFO |GWNotify-2/50       |ClientAbort
2016-01-26 00:00:00,051|TRACE|GWNotify-2/50       
|ClientAbortException:java.io.IOException: APR error: -32
org.apache.catalina.connector.ClientAbortException: java.io.IOException: APR 
error: -32
               at 
org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:353) 
~[catalina.jar:8.0.30]
               at 
org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:317) 
~[catalina.jar:8.0.30]
               at 
org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:110)
 ~[catalina.jar:8.0.30]

Caused by: java.io.IOException: APR error: -32
               at 
org.apache.coyote.http11.InternalAprOutputBuffer.writeToSocket(InternalAprOutputBuffer.java:291)
 ~[tomcat-coyote.jar:8.0.30]
               at 
org.apache.coyote.http11.InternalAprOutputBuffer.writeToSocket(InternalAprOutputBuffer.java:244)
 ~[tomcat-coyote.jar:8.0.30]
               at 
org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:213)
 ~[tomcat-coyote.jar:8.0.30]
               at 
org.apache.coyote.http11.AbstractOutputBuffer.flush(AbstractOutputBuffer.java:305)
 ~[tomcat-coyote.jar:8.0.30]
               at 
org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:765)
 ~[tomcat-coyote.jar:8.0.30]
               at org.apache.coyote.Response.action(Response.java:177) 
~[tomcat-coyote.jar:8.0.30]
               at 
org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:349) 
~[catalina.jar:8.0.30]
               ... 6 more

Finally after I stop server I see that GetRunnable client thread is still alive 
and waiting data from the server in “final String line = reader.readLine();”!!!

Reply via email to