首页 > Web开发 > 详细

WebSocket学习总结

时间:2020-04-17 17:40:41      阅读:71      评论:0      收藏:0      [点我收藏+]

  本文随便写了点自己对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

WebSocket学习总结

原文:https://www.cnblogs.com/chenkun-code/p/12721093.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!