WebSocket學習總結

来源:https://www.cnblogs.com/chenkun-code/archive/2020/04/17/12721093.html
-Advertisement-
Play Games

本文隨便寫了點自己對WebSoket通訊協議理解,在兩種框架上玩的Demo,然後踩了幾個坑還有沒填上的坑(歡迎評論指導一下)。 WebSocket是什麼?使用WebSocket的原因? WebSocket是網路通訊協議的一種。 提到網路通訊協議,我第一個就想到了HTTP協議,但是HTTP協議的一些特 ...


  本文隨便寫了點自己對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 OnError
116    * @author chenkun
117    */
118   OnError(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 => {
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

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 5.3 B+ 樹 B+ 樹是為磁碟或其他直接存儲輔助設備設計的一種平衡查找樹。在B+樹中,所有記錄都是按照鍵值大小順序存放在同一層的葉子節點上,由葉子節點指針進行連接,雙向鏈表連接。 5.3.1 B+ 樹的插入操作 考慮一下三種情況: Leaf Page滿 Index Page 滿 操作 No No ...
  • 一、ES6 基本認識 1、什麼是 ES6? ES6 指的是 ECMAScript 6.0,是JavaScript 語言的一個標準。其目標是使JavaScript 可以用來編寫複雜的大型的應用程式,成為企業級開發的語言。 2、ES6 與 JavaScript 的區別? ES6 是 JavaScript ...
  • p5.js完成星際穿越特效 歡迎關註我的 "博客" ,⬅️點他即可。 星際穿越,是模仿漫天星辰撲面而來的感覺。 最關鍵的在於對透視的掌握。 參考資料:The Coding Train 00 思路構想 1. 星星是一個圓,會隨機的出現在屏幕的任何位置; 2. 星星會從遠處到眼前: 圓的大小 來表示遠近 ...
  • ES6 axios執行原理 Axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中 http://www.axios-js.com/zh-cn/docs/ 1. axios.get('1111.json') .then(response => { consol ...
  • (1) 鏈接式:(外部引入.css文件) ( 用得比較多 ) <link>在html載入前就被引用 在網頁的<head></head>標簽對中用<link>引入外部樣式表,使用html規則引入外部css : <link href="./css/style.css" rel="stylesheet" ...
  • 一、塌陷 1.當position設置為:absolute或者fixed時,元素的display會轉換為block。(設置float也會產生這樣的效應) 2.正常情況下,div會被內容撐開,但是如果設置了 1. 的情況下,父元素就會產生 塌陷 ,失去高度。 解決辦法: 給父元素設置高度。 給父元素設置 ...
  • 在項目中用到cookie一般是用在註冊時的記住賬號密碼或保存固定時間的數據 // cookie 存儲setCookie(c_name, c_pwd, exdays) { // 設置存儲用戶名密碼 var exdate = new Date(); exdate.setTime(exdate.getTi ...
  • 1. 事件流(事件傳播) 描述的是從頁面接收事件的順序。 IE事件流是事件冒泡流,NetScape是事件捕獲流。 window: window document: document html: document.documentElement body: document.body div: doc ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...