当前位置: 移动技术网 > IT编程>开发语言>JavaScript > WebSocket学习总结

WebSocket学习总结

2020年04月18日  | 移动技术网IT编程  | 我要评论

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网