zoukankan      html  css  js  c++  java
  • Tomcat和Jetty对WebSocket的支持

    公司项目须要,了解了下眼下几种支持WebSocket的框架。曾经用jWebSocket做过一些项目。相对来说。改jWebSocket的源代码略复杂,也不是一天两天能搞定的。

    一调研才发现,如今非常多主流的web框架都已经開始支持WebSocket了,不得不感慨时间太快,科技进步太快,在微策略的几年真的荒废了。不多说,先记录下今天的研究。



    Tomcat:

           J2EE以下用的最多的容器应该就是tomcat了。说到tomcat对WebSocket的支持,不得不先提一下,眼下的WebSocket协议已经经过了好几代的演变。不同浏览器对此协议的支持程度也不同。因此,假设作为server。最理想的是支持尽可能多的WebSocket协议版本号。

    tomcat8真正支持jsr-356(包括对websocket的支持)。 tomcat7支持部分版本号的websocket实现不兼容jsr-356。因此,能用tomcat8的话,还是尽量用。


    代码实现相当简单,下面是一个列子,仅仅须要tomcat8的基本库,不须要其它依赖。

    import java.io.IOException;  
    import javax.websocket.OnClose;  
    import javax.websocket.OnMessage;  
    import javax.websocket.OnOpen;  
    import javax.websocket.Session;  
    import javax.websocket.server.ServerEndpoint;  
    
    
    @ServerEndpoint("/websocket")  
    public class WebSocketTest {  
      
        @OnMessage  
        public void onMessage(String message, Session session) throws IOException,  
                InterruptedException {  
            // Print the client message for testing purposes  
            System.out.println("Received: " + message);  
            // Send the first message to the client  
            session.getBasicRemote().sendText("This is the first server message");  
            // Send 3 messages to the client every 5 seconds  
            int sentMessages = 0;  
            while (sentMessages < 3) {  
                Thread.sleep(5000);  
                session.getBasicRemote().sendText("This is an intermediate server message. Count: " + sentMessages);  
                sentMessages++;  
            }  
            // Send a final message to the client  
            session.getBasicRemote().sendText("This is the last server message");  
        }  
      
        @OnOpen  
        public void onOpen() {  
            System.out.println("Client connected");  
        }  
      
        @OnClose  
        public void onClose() {  
            System.out.println("Connection closed");  
        }  
    }  


    Jetty:

           Jetty和Tomcat一样,也是一个Servlet的容器。假设说不同之处,那么最大的不同应该是Tomcat採用的是BIO处理方式,也就是说一个request会用一个线程去处理,即使是WebSocket这样的长连接,也是会独立开一个线程。

    作为一个普通的Webserver,tomcat能够轻松应对耗时比較短的Request/Response。可是假设换成是长连接的WebSocket。那麻烦就来了,对于上万用户的聊天和推送,总不能开上万个线程去处理吧。此时,Jetty的性能就体现出来了。Jetty採用的是NIO,一个线程能够处理多个WebSocket的长链接,假设你的需求是大量耗时比較长的request或者大量长连接,那么建议採用Jetty。


            Jetty对WebSocket的实现有点绕,Servlet不再是继承原来的HttpServlet。而是继承WebSocketServlet。此处要注意导入jetty-util.jar和jetty-websocket.jar两个包,否则可能会有class not found错误。

    ReverseAjaxServlet.java:

    import java.io.IOException;
    import java.util.Date;
    import java.util.Random;
     
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    import org.codehaus.jettison.json.JSONArray;
    import org.eclipse.jetty.websocket.WebSocket;
    import org.eclipse.jetty.websocket.WebSocketServlet;
     
    /**
     * @author Mathieu Carbou (mathieu.carbou@gmail.com)
     */
    public final class ReverseAjaxServlet extends WebSocketServlet {
     
        private final Endpoints endpoints = new Endpoints();
        private final Random random = new Random();
        private final Thread generator = new Thread("Event generator") {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.sleep(random.nextInt(5000));
                        endpoints.broadcast(new JSONArray().put("At " + new Date()).toString());
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        };
     
        @Override
        public void init() throws ServletException {
            super.init();
            generator.start();
        }
     
        @Override
        public void destroy() {
            generator.interrupt();
            super.destroy();
        }
         
        @Override
        public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
            return endpoints.newEndpoint();
        }
     
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            resp.getWriter().write("11111");
        }
    }

    Endpoints.java:

    package com.cn.test.chapter2.websocket;
    
    import org.eclipse.jetty.websocket.WebSocket;
    
    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
     
    /**
     * @author Mathieu Carbou (mathieu.carbou@gmail.com)
     */
    final class Endpoints {
        private final Queue<Endpoint> endpoints = new ConcurrentLinkedQueue<Endpoint>();
     
        void broadcast(String data) {
    //        for (Endpoint endpoint : endpoints) {
    //            endpoint.onMessage(data);
    //        }
        }
     
        void offer(Endpoint endpoint) {
            endpoints.offer(endpoint);
        }
     
        void remove(Endpoint endpoint) {
            endpoints.remove(endpoint);
        }
     
        public WebSocket newEndpoint() {
            return new Endpoint(this);
        }
    }

    Endpoint.java

    import java.io.IOException;
    import java.util.concurrent.ConcurrentLinkedQueue;
     
    
    
    
    import org.codehaus.jettison.json.JSONArray;
    import org.eclipse.jetty.websocket.WebSocket;
     
    /**
     * @author Mathieu Carbou (mathieu.carbou@gmail.com)
     */
    class Endpoint implements WebSocket.OnTextMessage  {
     
        protected Connection _connection;
         
        private Endpoints endpoints;
         
        private static int clientCounter = 0;
        private int clientId = clientCounter++;
         
        public Endpoint(Endpoints endpoints) {
            this.setEndpoints(endpoints);
        }
         
        @Override
        public void onClose(int code, String message) {
        	System.out.println("Client disconnected");  
        	
            this.endpoints.remove(this);
        }
     
        @Override
        public void onOpen(Connection connection) {
        	System.out.println("Client connected");  
            _connection = connection;
            try {
                this._connection.sendMessage(new JSONArray().put("ClientID = " + clientId).toString());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            endpoints.offer(this);
        }
     
        @Override
        public void onMessage(final String data) {
        	System.out.println("Received data: " + data);  
            this.endpoints.broadcast(data);
        }
     
        public Endpoints getEndpoints() {
            return endpoints;
        }
     
        public void setEndpoints(Endpoints endpoints) {
            this.endpoints = endpoints;
        }
    }




    辅助工具:

            在编写server最麻烦的是要写相应的client来測试,还好Chrome为我们攻克了这个问题。下载Chrome插件WebSocket Clinet能够轻松地和server建立连接,发送消息到server。

  • 相关阅读:
    在TreeView控件节点中显示图片
    PAT 甲级 1146 Topological Order (25 分)
    PAT 甲级 1146 Topological Order (25 分)
    PAT 甲级 1145 Hashing
    PAT 甲级 1145 Hashing
    PAT 甲级 1144 The Missing Number (20 分)
    PAT 甲级 1144 The Missing Number (20 分)
    PAT 甲级 1151 LCA in a Binary Tree (30 分)
    PAT 甲级 1151 LCA in a Binary Tree (30 分)
    PAT 甲级 1149 Dangerous Goods Packaging
  • 原文地址:https://www.cnblogs.com/lytwajue/p/6884854.html
Copyright © 2011-2022 走看看