WebSocket学习总结
程序员文章站
2022-06-28 18:39:57
本文随便写了点自己对WebSoket通讯协议理解,在两种框架上玩的Demo,然后踩了几个坑还有没填上的坑(欢迎评论指导一下)。 WebSocket是什么?使用WebSocket的原因? WebSocket是网络通讯协议的一种。 提到网络通讯协议,我第一个就想到了HTTP协议,但是HTTP协议的一些特 ......
本文随便写了点自己对websoket通讯协议理解,在两种框架上玩的demo,然后踩了几个坑还有没填上的坑(欢迎评论指导一下)。
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后,打开程序会出现白屏?
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项目中,直接创建一个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]
上一篇: Django 表单处理流程
下一篇: Java实现斗地主发牌的两种方法(集合)