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