Hi all, We have a simple servlet which implements Apache CometEvent for long polling connection on tomcat8. It works well when we used org.apache.coyote.http11.Http11NioProtocol, however, we have now changed to using org.apache.coyote.http11.Http11Nio2Protocol and it will not work properly.
Tomcat: v8.0.23 JDK: v1.8.0_45 OS: Windows server 2008 R2 The connector setting as below: <Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" connectionTimeout="60000" keystoreFile="D:\localhost.jks" keystorePass="******" /> The timeout of the event will not work as we have set it to 300 seconds(by event.setTimeout(300000)), the comet connection will be disconnected after 60 seconds which I believe is the connector connection timeout. And there will have thrown an exception as below 28-Oct-2016 15:04:33.748 SEVERE [http-nio2-8443-exec-5] org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process Error reading request, ignored java.lang.IllegalStateException: Reading not allowed due to timeout or cancellation at sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:249) at sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297) at org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:792) at org.apache.tomcat.util.net.Nio2Endpoint.awaitBytes(Nio2Endpoint.java:871) at org.apache.coyote.http11.Http11Nio2Protocol$Http11ConnectionHandler.release(Http11Nio2Protocol.java:180) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:722) at org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1073) at org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.run(Nio2Endpoint.java:1032) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) If the client makes the comet connection again after this, and the other client tries to send message. The comet will be END immediately and connection disconnected. The Connect servlet as below public class Connect extends HttpServlet implements CometProcessor { ... public void event(CometEvent event) throws IOException, ServletException { HttpServletRequest request = event.getHttpServletRequest(); HttpServletResponse response = event.getHttpServletResponse(); if (event.getEventType() == CometEvent.EventType.BEGIN) { String deviceid = request.getParameter("id"); MessageSender.getInstance().addConnection(deviceid, event); request.setAttribute("org.apache.tomcat.comet.timeout", 300 * 1000); event.setTimeout(300 * 1000); } else if (event.getEventType() == CometEvent.EventType.ERROR) { MessageSender.getInstance().removeConnection(event); event.close(); } else if (event.getEventType() == CometEvent.EventType.END) { MessageSender.getInstance().removeConnection(event); event.close(); } else if (event.getEventType() == CometEvent.EventType.READ) { throw new UnsupportedOperationException("This servlet does not accept data"); } } } And we have another Trigger servlet for sending message to client: public class Trigger extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { byte[] receieveByteArray = ByteUtil.getHttpServletRequestBody(req); sendTrigger(req, resp, receieveByteArray); } private void sendTrigger(HttpServletRequest req, HttpServletResponse resp, byte[] trigger) throws IOException, ServletException { try { MessageSender.getInstance().sendTrigger(deviceId, trigger); } catch (Exception e) { logger.error("Send trigger has thrown exception: ", e); } } } And the MessageSender class as below public class MessageSender { private static final Map<String, CometEvent> connections = new ConcurrentHashMap<String, CometEvent>(); public void addConnection(String deviceId, CometEvent event) { connections.put(deviceId, event); } public void removeConnection(CometEvent event) { while (connections.values().remove(event)) { } public static MessageSender getInstance() { return instance; } public void sendTrigger(String deviceId, byte[] triggerMessage) throws IOException, ConnectionNotFoundException { CometEvent comet = connections.get(deviceId); HttpServletResponse response = comet.getHttpServletResponse(); response.addHeader("Content-Length", Integer.toString(triggerMessage.length)); response.addHeader("Content-Language", "en-US"); ServletOutputStream servletOutputStream = response.getOutputStream(); servletOutputStream.write(triggerMessage); servletOutputStream.flush(); servletOutputStream.close(); comet.close(); // add for NIO2 connections.remove(deviceId); } } Thanks, Bruce