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: [email protected]
For additional commands, e-mail: [email protected]