Tomcat和Jetty對WebSocket的支持

jopen 10年前發布 | 124K 次閱讀 WebSocket 應用服務器

 

Tomcat:

       J2EE下面用的最多的容器應該就是tomcat了。說到tomcat對WebSocket的支持,不得不先提一下,目前的WebSocket協議已經經過了好幾代的演變,不同瀏覽器對此協議的支持程度也不同,因此,如果作為服務器,最理想的是支持盡可能多的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這種長連接,也是會獨立開一個線程。作為一個普通的Web服務器,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;  
        }  
    }  

 

 

輔助工具:

        在編寫服務器最麻煩的是要寫對應的客戶端來測試,還好Chrome為我們解決了這個問題。下載Chrome插件WebSocket Clinet可以輕松地和服務器建立連接,發送消息到服務器。

來自:http://blog.csdn.net/lrenjun/article/details/39934823

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!