這篇文章主要講解了“如何用單線程和定時任務分別實現WebSocket聊天室”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何用單線程和定時任務分別實現WebSocket聊天室”吧!
創(chuàng)新互聯建站于2013年創(chuàng)立,是專業(yè)互聯網技術服務公司,擁有項目成都網站建設、網站建設網站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元東光做網站,已為上家服務,為東光各地企業(yè)和個人服務,聯系電話:028-86922220
多媒體實時聊天
股票基金等數據報價
位置定位
社交訂閱
數據庫更新,前端實時顯示
要實現這種實時性較強的功能,以前經常采用的方法:輪詢和Comet技術
總結:都是基于請求-應答模式,不算真正意義上的實時技術,每一次請求應答,都要消耗一定流量。
WebSocket協議基于TCP協議實現,工作流程是這 樣的:瀏覽器通過JavaScript向服務端發(fā)出建立WebSocket連接的請求,在WebSocket連接建立成功后,客戶端和服務端就可以通過 TCP連接傳輸數據。因為WebSocket連接本質上是TCP連接,不需要每次傳輸都帶上重復的頭部數據, 其優(yōu)點:
通過第一次Http Request第一次建立連接之后,之后的數據交換都不要再重新發(fā)送Http Request,節(jié)省了寬帶資源
WebSocket協議是雙向通信協議,既可以發(fā)送又可以接受
多路復用即多個不同的URL可以復用同一個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 CopyOnWriteArraySetcopyOnWriteArraySet = 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--; } }
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"; } }
My WebSocket Test Welcome
6.結果展示
服務端:
感謝各位的閱讀,以上就是“如何用單線程和定時任務分別實現WebSocket聊天室”的內容了,經過本文的學習后,相信大家對如何用單線程和定時任務分別實現WebSocket聊天室這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯,小編將為大家推送更多相關知識點的文章,歡迎關注!