// ////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016-present // All Rights Reserved. // // Author: AlexWang // Date: 2016-08-27 21:40:49 // Last Modified by: AlexWang // Last Modified time: 2016-12-05 12:02:48 // QQ Email: 1669499355@qq.com // Description: 底层Socket管理器,保持一直在线及异常重连. // // ////////////////////////////////////////////////////////////////////////////// import Emiter from 'Emiter'; import Loger from 'Loger'; import GlobalConfig from 'GlobalConfig'; import EngineUtils from 'EngineUtils'; import LogManager from 'LogManager'; let loger = Loger.getLoger('EverSocket'); const MCU_MAX_RECONNECTION = 3;//最多重连次数 class EverSocket extends Emiter { constructor() { super(); this.sendToMcuList=[];//发送到MCU的数据记录 this.receiveFromMcuList=[];//接到MCU的数据记录 this.mcuReconnectCounter=0;//(重要)记录mcu连续重连的次数,最大连续8次就不再重连 this._connected = false; this._lastActiveTime = 0;//最后一次收到消息的时间 this._enableEverSocket = false; this.reConnectionCounter = 0;//重连次数 } begin(ip, port) { this._clearHistory(); loger.log('开始WebSocket应用.'); if (!ip) { loger.error('开始MCU连接->MCU连接地址无效'); } this._enableEverSocket = true; //this.wsURL = 'ws://' + ip + ':' + port; if (port) { this.wsURL = GlobalConfig.websocketProtocol + ip + ':' + port; } else { this.wsURL = GlobalConfig.websocketProtocol + ip; } this._newConnection(); } end() { loger.log('停止WebSocket应用.'); this._clear(); } switchSocketIp(ip, port) { /* if(port){ this.wsURL = 'ws://' + ip + ':' + port; }else { this.wsURL = 'ws://' + ip; }*/ if (port) { this.wsURL = GlobalConfig.websocketProtocol + ip + ':' + port; } else { this.wsURL = GlobalConfig.websocketProtocol + ip; } } get connected() { return this._connected; } send(data,type) { if (this._connected) { if (data) { let len=data.byteLength; //超过1024 警告提示 if (len> 1024) { loger.warn('发送到MCU的数据文件超过1k-->byteLength->'+len,"type:"+type); } //大于10k 不发送 if (len>=1024*10) { loger.warn('发送到MCU的数据文件超过10k-->byteLength->'+len,"type:"+type); return; } this.send2mcu(len,type); } this.websocket.send(data); } else { loger.warn('WebSocket未建立连接.消息忽略'); } } //统计发送到MCU的数据 /* * len 长度 * type 类型 * */ send2mcu(len,type){ /* this.sendToMcuList.push(""+len+":"+type); if(this.sendToMcuList.length>=200){ loger.log("发送到MCU数据统计->",this.sendToMcuList); this.sendToMcuList=[]; }*/ } //统计收到MCU的数据 /* * len 长度 * type 类型 * */ mcu2client(len,type){ /* this.receiveFromMcuList.push(""+len+":"+type); if(this.receiveFromMcuList.length>200){ loger.log("收到MCU数据统计->",this.receiveFromMcuList); this.receiveFromMcuList=[]; }*/ } _setConnected(isConn = true) { this._connected = isConn; if (this._connected) { this._emit(EverSocket.OPEN); } else { this._emit(EverSocket.CLOSED); } } _newConnection() { if (GlobalConfig.isHttps == true) { //https的时候替换所有80端口 this.wsURL = GlobalConfig.replacePort(this.wsURL, ":80", ""); } this.websocket = new WebSocket(this.wsURL); this.websocket.binaryType = 'arraybuffer'; this.websocket.onopen = this._onOpen.bind(this); this.websocket.onclose = this._onClose.bind(this); this.websocket.onerror = this._onError.bind(this); this.websocket.onmessage = this._onMessage.bind(this); } _reConnection() { this._clear(); window.clearTimeout(this.reConnectionTimeout); this.reConnectionCounter++; this.mcuReconnectCounter++; if (this.reConnectionCounter > MCU_MAX_RECONNECTION) { if( this.mcuReconnectCounter>=MCU_MAX_RECONNECTION*2){ loger.warn('MCU断线重连->已经达到最大重连次数->停止重连'); this._emit(EverSocket.ERROR, EverSocket.ERR_SOCKET_MAX_RECONNECT_FAILED); return; } this._emit(EverSocket.ERROR, EverSocket.ERR_SOCKET_RECONNECT_FAILED); this.reConnectionCounter = 0; } this.reConnectionTimeout = window.setTimeout(() => { loger.log('MCU断线重连->', this.reConnectionCounter); window.clearTimeout(this.reConnectionTimeout); this._newConnection(); }, EverSocket.RECONN_INTERVAL); } _clear() { loger.log('WebSocket-Timers销毁'); window.clearInterval(this.pingTimer); window.clearInterval(this.pongTimer); window.clearInterval(this.reConnectionTimeout); this._setConnected(false);//先设置状态 this._enableEverSocket = false; if (this.websocket == null) { // loger.log('WebSocket,Timers已经销毁'); return; } this.websocket.onopen = undefined; this.websocket.onclose = undefined; this.websocket.onerror = undefined; this.websocket.onmessage = undefined; try { this.websocket.close(); } catch (e) { loger.log('ignore errors'); } this.websocket = undefined; } _clearHistory() { //loger.log('WebSocket->清除记录'); window.clearInterval(this.pingTimer); window.clearInterval(this.pongTimer); window.clearInterval(this.reConnectionTimeout); //this._setConnected(false);//先设置状态 this._connected = false; this._enableEverSocket = false; if (this.websocket == null) { //loger.log('WebSocket->已经销毁'); return; } this.websocket.onopen = undefined; this.websocket.onclose = undefined; this.websocket.onerror = undefined; this.websocket.onmessage = undefined; try { this.websocket.close(); } catch (e) { loger.log('ignore errors'); } this.websocket = undefined; } _onOpen() { loger.log('MCU连接成功', this.wsURL); this.reConnectionCounter = 0; this.mcuReconnectCounter=0; //启动心跳,检查socket链接状态 this.pingTimer = window.setInterval(this._sendPingHandler.bind(this), EverSocket.PING_INTERVAL); this.pongTimer = window.setInterval(this._checkPongHandler.bind(this), EverSocket.PONG_INTERVAL); this._setConnected(); } _onClose(closeEvent) { loger.log(`MCU连接断开-CODE:${closeEvent.code} REASON:${closeEvent.reason} CLEAN: ${closeEvent.wasClean}`, this.wsURL); this._reConnection(); } _onError() { loger.log('WebSocket->ERROR->准备重连'); this._connected = false; this._reConnection(); } _onMessage(messageEvent) { this._lastActiveTime = Date.now(); const bufferData = messageEvent.data; //loger.log('RECEIVE-->byteLength->',bufferData.byteLength); let len=bufferData.byteLength; if (len> 0) { this._emit(EverSocket.MESSAGE, bufferData); this.mcu2client(len,"msg"); }else { this.mcu2client(0,"pong"); } } _sendPingHandler() { if (this._connected) { this.send2mcu(0,"ping"); this.websocket.send(new ArrayBuffer); } else { this._reConnection(); } } _checkPongHandler() { let pongTime = Date.now(); if (this._lastActiveTime && this._lastActiveTime >= pongTime - EverSocket.PONG_INTERVAL && this._lastActiveTime <= pongTime ) { } else { loger.warn('服务器PINGPONG超时->准备重连',"lastActiveTime:"+this._lastActiveTime,"pongTime:"+pongTime); this._reConnection(); } } } /*//修改之前的 EverSocket.prototype.PONG_INTERVAL = EverSocket.PONG_INTERVAL = 5000; EverSocket.prototype.PING_INTERVAL = EverSocket.PING_INTERVAL = 3000; EverSocket.prototype.RECONN_INTERVAL = EverSocket.RECONN_INTERVAL = 2000;*/ //20170223-mcu服务端修改了心跳的逻辑,如果客户端30秒没有请求,就会按离开的处理 //目前客户端发送心跳请求的空数据,服务端不会每次都回,暂定为10秒心跳一次 EverSocket.prototype.PONG_INTERVAL = EverSocket.PONG_INTERVAL = 21000;// EverSocket.prototype.PING_INTERVAL = EverSocket.PING_INTERVAL = 10000;//心跳间隔 EverSocket.prototype.RECONN_INTERVAL = EverSocket.RECONN_INTERVAL = 5000;//重连的间隔 EverSocket.prototype.ERR_SOCKET_RECONNECT_FAILED = EverSocket.ERR_SOCKET_RECONNECT_FAILED = 20001;//MCU自动重连失败, EverSocket.prototype.ERR_SOCKET_MAX_RECONNECT_FAILED = EverSocket.ERR_SOCKET_MAX_RECONNECT_FAILED = 20002;//MCU自动重连失败,已经达到最大重连次数 EverSocket.prototype.CONNECTING = EverSocket.CONNECTING = 0; EverSocket.prototype.OPEN = EverSocket.OPEN = 1; EverSocket.prototype.CLOSING = EverSocket.CLOSING = 2; EverSocket.prototype.CLOSED = EverSocket.CLOSED = 3; EverSocket.prototype.MESSAGE = EverSocket.MESSAGE = 4; EverSocket.prototype.ERROR = EverSocket.ERROR = 5; export default new EverSocket();