真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯網站制作重慶分公司

如何用單線程和定時任務分別實現WebSocket聊天室

這篇文章主要講解了“如何用單線程和定時任務分別實現WebSocket聊天室”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何用單線程和定時任務分別實現WebSocket聊天室”吧!

創(chuàng)新互聯建站于2013年創(chuàng)立,是專業(yè)互聯網技術服務公司,擁有項目成都網站建設、網站建設網站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元東光做網站,已為上家服務,為東光各地企業(yè)和個人服務,聯系電話:028-86922220

1.需求場景

  • 多媒體實時聊天

  • 股票基金等數據報價

  • 位置定位

  • 社交訂閱

  • 數據庫更新,前端實時顯示

要實現這種實時性較強的功能,以前經常采用的方法:輪詢Comet技術

  • 輪詢:要求客戶端已設定的時間間隔周期性地向服務器端發(fā)送請求,頻繁查詢數據是否變動。缺點:過多不必要的請求,浪費流量和服務器資源。

  • Comet技術:可以分為長輪詢和流技術。長輪詢改進上述輪詢,減少無用的請求,設定過期時間,當數據過期后才會向服務器端發(fā)送請求,適合數據改動不頻繁的場景;流技術是指客戶端通過一個隱藏的窗口與服務器建立一個HTTP長連接,不斷更新連接狀態(tài)保持連接不斷開。

總結:都是基于請求-應答模式,不算真正意義上的實時技術,每一次請求應答,都要消耗一定流量。

2.WebSocket原理

WebSocket協議基于TCP協議實現,工作流程是這 樣的:瀏覽器通過JavaScript向服務端發(fā)出建立WebSocket連接的請求,在WebSocket連接建立成功后,客戶端和服務端就可以通過 TCP連接傳輸數據。因為WebSocket連接本質上是TCP連接,不需要每次傳輸都帶上重復的頭部數據, 其優(yōu)點:

  • 通過第一次Http Request第一次建立連接之后,之后的數據交換都不要再重新發(fā)送Http Request,節(jié)省了寬帶資源

  • WebSocket協議是雙向通信協議,既可以發(fā)送又可以接受

  • 多路復用即多個不同的URL可以復用同一個Websocket連接

如何用單線程和定時任務分別實現WebSocket聊天室

3.打造Websocket聊天室

溫馨提示:基于IAEA+SpringBoot+Gradle開發(fā),得益于SpringBoot提供的自動配置,只需要通過簡單注解@ServerEndpoint就能創(chuàng)建WebSocket服務端,再通過簡單的回調函數就能完成WebSocket服務端的編寫!
  • build.gadle

	//spring-boot-starter-websocket的依賴springboot的高級組件會自動引用基礎的組件,
	// 像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter
	compile group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '2.1.6.RELEASE'
       //thymeleaf
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.1.6.RELEASE'
  • 創(chuàng)建一個WebSocketConfig

package com.example.SmartHome.config;


import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/*
 *@Description:  自動注冊使用了@ServerEndpoint注解聲明的Websocket endpoint
 *@ClassName: WebSocketConfig
 *@Author: zzq
 *@Date: 2019/7/7 11:01
 *@Version: 1.0
 */
@Configuration
@Component
@ConditionalOnWebApplication

public class WebSocketConfig {
    /**
     * 自動注冊使用了@ServerEndpoint注解聲明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
提醒:ServerEndpointExporter 是由Spring官方提供的標準實現,用于掃描ServerEndpointConfig配置類和@ServerEndpoint注解實例。使用規(guī)則:1.如果使用默認的嵌入式容器 比如Tomcat 則必須手工在上下文提供ServerEndpointExporter。2. 如果使用外部容器部署war包,則不要提供提供ServerEndpointExporter,因為此時SpringBoot默認將掃描服務端的行為交給外部容器處理。
  • 創(chuàng)建WebSocket服務器

    核心思路:
    
    ① 通過注解@ServerEndpoint來聲明實例化WebSocket服務端。
    ② 通過注解@OnOpen、@OnMessage、@OnClose、@OnError 來聲明回調函數。

     

    事件類型注解事件描述
    open@OnOpen當打開連接后觸發(fā)
    message@OnMessage當接受客戶端消息時觸發(fā)
    error@OnError當通信異常時觸發(fā)
    close@OnClose當連接關閉時觸發(fā)
    package com.example.SmartHome.server;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    /*
     *@Description: WebSocketServer服務器端
     *@ClassName: WebSocketServer
     *@Author: zzq
     *@Date: 2019/7/3 17:05
     *@Version: 1.0
     */
    //ServerEndpoint這個bean會自動注冊使用了@ServerEndpoint注解聲明的Websocket endpoint。
    // 要注意,如果使用獨立的servlet容器,而不是直接使用springboot的內置容器,
    // 就不要注入ServerEndpointExporter,
    // 因為它將由容器自己提供和管理。
    /**
     * @ServerEndpoint 注解是一個類層次的注解,它的功能主要是將目前的類定義成一個websocket服務器端,
     * 注解的值將被用于監(jiān)聽用戶連接的終端訪問URL地址,客戶端可以通過這個URL來連接到WebSocket服務器端
     */
    @ServerEndpoint("/websocket")
    @Component  //它的主要作用就是將這個監(jiān)聽器納入到Spring容器中進行管理
    
    public class WebSocket {
    //    MyThread thread1=new MyThread();
    //    Thread  thread  =new Thread(thread1);
        //每個客戶端都會有相應的session,服務端可以發(fā)送相關消息
        private Session session;
        public static int onlineCount = 0;
        //J.U.C包下線程安全的類,主要用來存放每個客戶端對應的webSocket連接
        private static CopyOnWriteArraySet copyOnWriteArraySet = new CopyOnWriteArraySet();
    
        /**
         * @Name:onOpen
         * @Description:打開連接。進入頁面后會自動發(fā)請求到此進行連接
         */
        @OnOpen
        public void onOpen(Session session) throws IOException {
            this.session = session;
            copyOnWriteArraySet.add(this);
            addOnlineCount();
            System.out.println("websocket有新的連接, 總數:" + getOnlineCount());
            sendMessage("成功連接");
    
        }
    
        /**
         * @Name:onClose
         * @Description:用戶關閉頁面,即關閉連接
         */
        @OnClose
        public void onClose() {
            copyOnWriteArraySet.remove(this);
            shortOnlineCount();
            System.out.println("websocket連接斷開, 總數:" + getOnlineCount());
        }
    
        /**
         * @Name:onMessage
         * @Description:收到客戶端消息后調用的方法
         */
        @OnMessage
        public void onMessage(String message,Session session) throws IOException {
    
            System.out.println("websocket收到客戶端發(fā)來的消息:" + message);
            for(WebSocket webSocket:copyOnWriteArraySet){
                webSocket.sendMessage(message);
            }
    
        }
    
        /**
         * @Name:onError
         * @Description:出現錯誤
         */
        @OnError
        public void onError(Session session, Throwable error) {
            System.out.println("發(fā)生錯誤:" + error.getMessage() + "; sessionId:" + session.getId());
            error.printStackTrace();
        }
        public void sendMessage(String message) throws IOException {
            this.session.getBasicRemote().sendText(message);
            // this.session.getAsyncRemote().sendText(message);
        }
    
    
        public void sendMessage(Object object) {
            //遍歷客戶端
            for (WebSocket webSocket : copyOnWriteArraySet) {
                System.out.println("websocket廣播消息:" + object.toString());
                try {
                    //服務器主動推送
                    webSocket.session.getBasicRemote().sendObject(object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * @Name:sendMessage
         * @Description:用于發(fā)送給客戶端消息(群發(fā))
         */
        public static void sendInfo(String message) {
            //遍歷客戶端
            for (WebSocket webSocket : copyOnWriteArraySet) {
                System.out.println("websocket廣播消息:" + message);
                try {
                    //服務器主動推送
                    webSocket.session.getBasicRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * @Name:sendMessage
         * @Description:用于發(fā)送給指定客戶端消息
         */
        public void sendMessage(String sessionId, String message) throws IOException {
            Session session = null;
            WebSocket tempWebSocket = null;
            for (WebSocket webSocket : copyOnWriteArraySet) {
                if (webSocket.session.getId().equals(sessionId)) {
                    tempWebSocket = webSocket;
                    session = webSocket.session;
                    break;
                }
            }
            if (session != null) {
                tempWebSocket.session.getBasicRemote().sendText(message);
            } else {
                System.out.println("沒有找到你指定ID的會話:{}" + "; sessionId:" + sessionId);
            }
        }
    
        public static  synchronized int getOnlineCount(){
            return onlineCount;
        }
        public static synchronized void addOnlineCount(){
            WebSocket.onlineCount++;
        }
        public static  synchronized void shortOnlineCount(){
            WebSocket.onlineCount--;
        }
    
    }

    4.Controller類

package com.example.SmartHome.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/*
 *@Description: TODO
 *@ClassName: ChatController
 *@Author: zzq
 *@Date: 2019/7/9 16:56
 *@Version: 1.0
 */
@Controller
public class ChatController {
    @RequestMapping("/websocket")
    public String init() {
        return "websocket.html";
    }
}

5.前端代碼


  
    My WebSocket Test

 Welcome
 Send Close  
       var websocket = null;     //判斷當前瀏覽器是否支持WebSocket     if('WebSocket' in window){         websocket = new WebSocket("ws:2559qs1996.qicp.vip:20422/websocket");     }     else{         alert('Not support websocket')     }     //連接發(fā)生錯誤的回調方法     websocket.onerror = function(){         setMessageInnerHTML("error");     };     //連接成功建立的回調方法     websocket.onopen = function(event){         setMessageInnerHTML("open");     }     //接收到消息的回調方法     websocket.onmessage = function(event){         setMessageInnerHTML(event.data);     }     //連接關閉的回調方法     websocket.onclose = function(){         setMessageInnerHTML("close");     }     //監(jiān)聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。     window.onbeforeunload = function(){         websocket.close();     }     //將消息顯示在網頁上     function setMessageInnerHTML(innerHTML){         document.getElementById('message').innerHTML += innerHTML + '
';     }     //關閉連接     function closeWebSocket(){         websocket.close();     }     //發(fā)送消息     function send(){         var message = document.getElementById('text').value;         websocket.send(message);     }  

6.結果展示

如何用單線程和定時任務分別實現WebSocket聊天室

服務端:

如何用單線程和定時任務分別實現WebSocket聊天室

感謝各位的閱讀,以上就是“如何用單線程和定時任務分別實現WebSocket聊天室”的內容了,經過本文的學習后,相信大家對如何用單線程和定時任務分別實現WebSocket聊天室這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯,小編將為大家推送更多相關知識點的文章,歡迎關注!


當前名稱:如何用單線程和定時任務分別實現WebSocket聊天室
文章網址:http://weahome.cn/article/pecgji.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部