本文隨便寫了點自己對WebSoket通訊協議理解,在兩種框架上玩的Demo,然后踩了幾個坑還有沒填上的坑(歡迎評論指導一下),
WebSocket是什么?使用WebSocket的原因?
WebSocket是網路通訊協議的一種,
提到網路通訊協議,我第一個就想到了HTTP協議,但是HTTP協議的一些特性我想不用多說,大家也都是了解的,像無法保持長連接(由于功能需要,已有大佬整出保持長連接的方式);發起端只能是客戶端;這些特性讓我們在實際開發某些功能遇到了極大的麻煩,所以在HTML5推出WebSocket標準,讓瀏覽器和服務器建立了無限制的雙全工通信,雙方可以互發訊息,
WebSocket框架上使用
angular(7.2.2)+ ionic(4.0.0)
這是一個移動端應用程式,在angular框架中,我慣用服務(service)來處理業務,因此直接在服務管理的檔案夾創建一個WebSocket的服務(ng generate service WebSocket),WebSocket服務里包含創建連接,重連機制,心跳檢測,計算運行時間等基礎功能(詳細寫法可見代碼),
接下來可以在app全域新增一個WebSocket組件,ngOnInit生命鉤子去建立連接,往組件中寫入收發訊息代碼,會解決網頁重繪導致WebSocket實體被清除,WebSocket組件在生命周期再次連接,
問題1:我在ionic中創建了WebSocket組件,用于重繪重連(app沒有重繪,實際操作只會在瀏覽器除錯中出現),在瀏覽器上除錯可以正常使用并且不會斷開連接,但是當我將代碼打包編譯成apk后,打開程式會出現白屏?
問題2:因為我脫離了組件使用WebSocket,單純的呼叫服務,我實際組件中需要使用的資料也保存在服務之中,導致訊息回傳資料不會更新視圖?
1 import { Injectable } from '@angular/core'; 2 import { interval, Subject } from 'rxjs'; 3 4 @Injectable({ 5 providedIn: 'root' 6 }) 7 export class WebsocketService { 8 public websocket: WebSocket; // websocket通訊物件 9 url: string = null; // websocket連接地址 10 isConnectSuccess: boolean = false; // 當前連接狀態 11 isReconnect: boolean = false; // 是否正在重連 12 reconnectSubscription: any = null; // 定時重新連接物件 13 reconnectPeriod: number = 20 * 1000; // 重連失敗,定時重新連接的時間刻度,20s 14 heartCheckSubscription: any = null; // 定時心跳檢查物件 15 heartCheckPeriod: number = 10 * 60 * 1000; // 定時心跳檢測的時間刻度,10min 16 runTimeSubscription: any = null; // 記錄運行時間物件 17 runTimePeriod: number = 10 * 60 * 1000; // 記錄運行時間的時間刻度,10min 18 19 constructor( 20 private messageService: MessageService, 21 ) { } 22 23 /** 24 * @description 更新連接地址,創建WebSocket實體,添加連接打開,連接關閉,連接例外,接收訊息事件 25 * @method Connect 26 * @author chenkun 27 */ 28 Connect(url?: string) { 29 const ip = localStorage.getItem('ipAddress'); 30 if (ip) { 31 this.url = "ws://" + ip + ":40100"; 32 } else { 33 this.messageService.ErrorToast('當前設備沒有服務器地址'); 34 } 35 if (!!url) { 36 this.url = url; 37 } 38 if (this.url) { 39 this.websocket = new WebSocket(this.url); 40 } 41 this.websocket.onopen = (event) => { 42 this.OnOpen(event); 43 } 44 this.websocket.onclose = (event) => { 45 this.OnClose(event); 46 } 47 this.websocket.onerror = (event) => { 48 this.OnError(event); 49 } 50 this.websocket.onmessage = (event) => { 51 this.OnMessage(event); 52 } 53 } 54 55 /** 56 * @description 檢測當前websocket服務狀態 57 * @method CheckWebSocket 58 * @author chenkun 59 */ 60 CheckWebSocket() { 61 const websocket = this.websocket; 62 if (websocket) { 63 switch (websocket.readyState) { 64 case 0: 65 // 沒有連接 66 break; 67 case 1: 68 // 連接成功 69 break; 70 case 2: 71 // 連接正在關閉 72 break; 73 case 3: 74 // 連接關閉 75 break; 76 } 77 } else { 78 // WebSocket實體物件沒有,重繪瀏覽器會導致這種情況 79 } 80 } 81 82 /** 83 * @description WebSocket連接成功時觸發事件,當前連接狀態改為成功,如果當前正在重連則停止重新連接,開啟心跳檢測和計算連接運行時間 84 * @param event 連接成功時,服務端發回的事件物件 85 * @method OnOpen 86 * @author chenkun 87 */ 88 OnOpen(event: any) { 89 // 連接成功 90 this.isConnectSuccess = true; 91 if (this.isReconnect) { 92 this.StopReconnect(); 93 this.StartHeartCheck(); 94 this.StartCalcRunTime(); 95 } 96 } 97 98 /** 99 * @description WebSocket連接關閉時觸發事件,當前連接狀態改為失敗,開始嘗試重新連接,停止計算運行時間 100 * @param event 連接失敗時,服務端發回的事件物件 101 * @method OnClose 102 * @author chenkun 103 */ 104 OnClose(event: any) { 105 // 連接關閉 106 this.isConnectSuccess = false; 107 this.websocket.close(); 108 this.StartReconnect(); 109 this.StopRunTime(); 110 } 111 112 /** 113 * @description WebSocket連接例外時觸發事件,出現例外會同時觸發連接關閉事件 114 * @param event 連接例外時,服務端發回的事件物件 115 * @method one rror 116 * @author chenkun 117 */ 118 one rror(event: any) { 119 // 連接例外 120 this.isConnectSuccess = false; 121 } 122 123 /** 124 * @description WebSocket服務端發回訊息接收事件 125 * @param event 服務端發回訊息的事件物件 126 * @method OnMessage 127 * @author chenkun 128 */ 129 OnMessage(event: any) { 130 // 服務器回傳的訊息 131 console.log(event); 132 } 133 134 /** 135 * @description WebSocket客戶端發送訊息給服務端,發送訊息前先檢查列印服務是否連接 136 * @param message 客戶端發送的訊息 137 * @method SendMessage 138 * @author chenkun 139 */ 140 SendMessage(message: any) { 141 // 檢查WebSocket的狀態,連接存在時才能發送訊息 142 this.CheckWebSocket(); 143 if (this.websocket) { 144 if (this.websocket.readyState === 1) { 145 this.websocket.send(message); 146 } 147 } 148 } 149 150 /** 151 * @description 開始定時重連WebSocket服務端,如果連接成功,停止重連并且退出,如果正在重連直接退出 152 * 如果都沒有,改為正在重連狀態,訂閱計時器回圈發送呼叫連接 153 * @method StartReconnect 154 * @author chenkun 155 */ 156 StartReconnect() { 157 if (this.isConnectSuccess) { 158 this.StopReconnect(); 159 return; 160 } 161 if (this.isReconnect) { 162 return; 163 } 164 this.isReconnect = true; 165 this.reconnectSubscription = interval(this.reconnectPeriod).subscribe(async (value) => { 166 console.log(`重連:${value}次`); 167 const url = this.url; 168 this.Connect(url); 169 }); 170 } 171 172 /** 173 * @description 更改不再重連狀態,取消訂閱計時器回圈發送重復連接 174 * @method StopReconnect 175 * @author chenkun 176 */ 177 StopReconnect() { 178 this.isReconnect = false; 179 // 取消訂閱定時重新連接事件 180 if (typeof this.reconnectSubscription !== 'undefined' && this.reconnectSubscription != null) { 181 this.reconnectSubscription.unsubscribe(); 182 } 183 } 184 185 /** 186 * @description 訂閱計時器查詢心跳檢測,如果當前處于連接成功狀態不做處理,如果沒有連接,就停止心跳檢測,開始重新連接 187 * @method StartHeartCheck 188 * @author chenkun 189 */ 190 StartHeartCheck() { 191 this.heartCheckSubscription = interval(this.heartCheckPeriod).subscribe((value) => { 192 if (this.websocket != null && this.websocket.readyState === 1) { 193 console.log(value, '連接狀態成功,發送訊息保持連接'); 194 } else { 195 this.StopHeartCheck(); 196 this.StartReconnect(); 197 } 198 }); 199 } 200 201 /** 202 * @description 取消訂閱計時器查詢心跳檢測 203 * @method StopHeartCheck 204 * @author chenkun 205 */ 206 StopHeartCheck() { 207 if (typeof this.heartCheckSubscription !== 'undefined' && this.heartCheckSubscription != null) { 208 this.heartCheckSubscription.unsubscribe(); 209 } 210 } 211 212 /** 213 * @description 訂閱計時器計算連接運行時間 214 * @method StartCalcRunTime 215 * @author chenkun 216 */ 217 StartCalcRunTime() { 218 this.runTimeSubscription = interval(this.runTimePeriod).subscribe(value =https://www.cnblogs.com/chenkun-code/p/> { 219 console.log('運行時間', `${value}分鐘`); 220 }); 221 } 222 223 /** 224 * @description 取消訂閱計時器計算連接運行時間 225 * @method StopRunTime 226 * @author chenkun 227 */ 228 StopRunTime() { 229 if (typeof this.runTimeSubscription !== 'undefined' && this.runTimeSubscription !== null) { 230 this.runTimeSubscription.unsubscribe(); 231 } 232 } 233 }
vue(2.5.2)+ element-ui(2.4.11)
Vue專案中,直接創建一個SocketHelper.vue的子組件,并且直接在App.vue引入組件,借助Vuex來傳遞資料,借助eventBus收發訊息事件,
<template> <div id="app" class="app"> <socket /> <router-view /> </div> </template> <script> import socket from "./public-components/SocketHelper.vue"; export default { name: "App", components: { socket }, }; </script>
<template> <div></div> </template> <script> import store from "../vuex/store"; export default { data() { return { websocket: null, eventBus: this.store.state.eventBus }; }, created() { this.initWebSocket(); }, destroyed() { this.websocketclose(); }, methods: { //初始化weosocket initWebSocket() { const url = "ws:" + this.configs.ServiceAddress + ":40100"; //ws地址 this.websocket = new WebSocket(url); this.websocket.onopen = this.websocketonopen; this.websocket.onerror = this.websocketonerror; this.websocket.onclose = this.websocketclose; this.websocket.onmessage = this.websocketonmessage; this.eventBus.$off("WebSocketSendContent"); this.eventBus.$on("WebSocketSendContent", res => { this.websocketsend(res); }); }, websocketonopen() { // 連接成功 }, websocketonerror(e) { // 連接例外 }, websocketclose(e) { // 連接關閉 this.initWebSocket(); }, websocketonmessage(e) { // 接收訊息 }, websocketsend(agentData) { // 發送訊息 if (this.websocket.readyState === 1) { this.websocket.send(agentData); } }, } }; </script>
參考來自
[angular整合websocket] https://www.jianshu.com/p/b04c34df128d
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/117318.html
標籤:JavaScript
下一篇:JS事件總結
