• 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。

  • 相关阅读:
    JAVA正则表达式判断元音
    JAVA正则表达式校验qq号码
    方法
    数组
    Java基础随笔3
    LDA背景资料
    scrapy系列(四)——CrawlSpider解析
    scrapy系列(三)——基础spider源码解析
    scrapy系列(二)——startproject、genspider创建项目与模板使用
    我眼中的机器学习(四) 快速寻找最优解
  • 原文地址:https://www.cnblogs.com/lytwajue/p/6884854.html
Copyright © 2020-2023  润新知