Hi Christoph
 
There is such option in my app (heartbeats from server to client) but I’m
curious why connection becomes stale if I don’t send any heartbeats.



On 29/01/16 16:04, "Christoph Nenning" <christoph.nenn...@lex-com.net>
wrote:

>> 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