欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WebSocket学习总结

程序员文章站 2022-06-28 18:39:57
本文随便写了点自己对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]