0
  • How can I set the comet event timeout on NIO2 protocol?
  • How to well handle the socket connection on NIO2 protocol?(e.g., close connection)

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 change to using org.apache.coyote.http11.Http11Nio2Protocol and it will not work properly.

On NIO, the client can make a comet connection to a Connect servlet by POST and the other client can send message by POST to Trigger servlet. Every 300 seconds we will timeout the comet and the client app will make comet connection again.

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);
    }
}

After we have changed the connector setting of tomcat http protocol to NIO2 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 event will not work as we have set it to 300 seconds, 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 make the comet connection again after this, and the other client try to send message to Trigger servlet. The comet will be END immediately and connection disconnected.

Any help is appreciated

Bruce
  • 647
  • 2
  • 12
  • 30
  • Comet support has been deprecated. Most folks have switched to using WebSocket. – Mark Thomas Oct 29 '16 at 13:53
  • Hi Mark, thanks for the reply. I see, but we still try to figure out the root cause and maybe find out some workaround(if possilble) for the temporary solution, since we have number of comet implementation. – Bruce Oct 29 '16 at 14:59

0 Answers0