On 01/11/2016 09:44, Bruce Huang wrote: > 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 first thing to do is to test the latest 8.0.x release. Keep in mind that Comet is deprecated so if there is still a bug in 8.0.x, fixing it might not be a priority. Switching back to NIO may be a better option. Mark > > 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 > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org