> 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();”!!!


Hi,

I would send some keep-alive data (e.g. current timestamp) maybe once per 
day or once every 5 hours. The client can just dismiss that data. This 
might help in some situations but there is no 100% guarantee that it works 
always.


Regards,
Christoph


This Email was scanned by Sophos Anti Virus

Reply via email to