-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Maxim,
On 2/1/16 4:53 AM, Maxim Neshcheret wrote: > 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. Any networking component can decide that a connection has been open for too long. It could be the OS's TCP/IP stack, a software firewall on either end, etc. Or the client could have gone to sleep (e.g. OS sleep mode). Your heartbeats keep it from going to sleep , maybe? If you want a 10-day connection to stay open, heartbeats are the only way to do it. Presumably, you can catch the heartbeat failure? Under that condition, take appropriate action. - -chris > 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 > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iEYEARECAAYFAlavk4EACgkQ9CaO5/Lv0PC8SQCgiq7KSXyhgKH37xNI067lLO0C FoEAn2yZn3uXHVLAz7+Ae/itrYDieyMT =3LYs -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org