Explorar el Código

解决WebSocket断开会有延迟问题

li.shaoyi hace 3 años
padre
commit
dfbe455ced
Se han modificado 2 ficheros con 55 adiciones y 39 borrados
  1. 10 6
      src/services/index.ts
  2. 45 33
      src/utils/websocket/index.ts

+ 10 - 6
src/services/index.ts

@@ -100,16 +100,20 @@ export default new (class LifeCycleCtr {
 
     /** 主动关闭行情服务 */
     closeQuote() {
-        this.Socket['quote'].close();
+        if (this.Socket['quote'].connState !== 'Unconnected') {
+            this.Socket['quote'].close();
+        }
     }
 
     /** 主动关闭长链接 */
     closeServer(): void {
-        this.Socket['trade'].close();
-        this.dataCenter.reset();
-        // sessionStorage.clear();
-        // localStorageUtil.removeItem('loginData');
-        timerUtil.clearAll();
+        if (this.Socket['trade'].connState !== 'Unconnected') {
+            this.Socket['trade'].close();
+            this.dataCenter.reset();
+            // sessionStorage.clear();
+            // localStorageUtil.removeItem('loginData');
+            timerUtil.clearAll();
+        }
     }
 
     /** 处理行情相关信息 */

+ 45 - 33
src/utils/websocket/index.ts

@@ -1,3 +1,4 @@
+import { v4 } from 'uuid'
 import { Package40, Package50 } from './package';
 import moment from 'moment'
 
@@ -77,6 +78,8 @@ export class MTP2WebSocket<T extends Package40 | Package50> {
     /** 重连状态发生改变时的回调 */
     onReconnectChangeState?: (obj: MTP2WebSocket<T>, state: ReconnectChangeState) => void;
 
+    /** 实例唯一标识 */
+    private uuid = '';
     /** 报文类型,0 - 4.0行情报文,1 - 5.0交易报文 */
     private packageType;
     /** WebSocket 对象 */
@@ -104,8 +107,6 @@ export class MTP2WebSocket<T extends Package40 | Package50> {
     private beatInterval = 10 * 1000;
     /**  心跳回复超时时间,默认为15秒 */
     private beatTimeoutInterval = 15 * 1000;
-    /** 外部是否要求停止断网重连操作标志 */
-    private isBrokenReconnecting = false;
 
     private readyState?: Promise<MTP2WebSocket<T>>;
 
@@ -128,11 +129,13 @@ export class MTP2WebSocket<T extends Package40 | Package50> {
             this.stopBeatTimer();
             this.host = host || this.host;
             this.connState = 'Connecting';
-            this.isBrokenReconnecting = false;
             console.log(this.packageType, this.host, '正在连接');
 
             this.readyState = new Promise((resolve, reject) => {
+                const uuid = v4();
+                this.uuid = uuid;
                 this.socket = new WebSocket(this.host);
+
                 // 连接成功
                 this.socket.onopen = () => {
                     console.log(this.packageType, this.host, '连接成功');
@@ -141,16 +144,13 @@ export class MTP2WebSocket<T extends Package40 | Package50> {
                     this.onConnected && this.onConnected(this);
                     resolve(this);
                 }
-                // 连接断开
+                // 连接断开(CLOSING有可能延迟)
                 this.socket.onclose = () => {
-                    console.warn(this.packageType, this.host, '连接已断开');
-                    this.socket = undefined;
-                    this.readyState = undefined;
-                    this.connState = 'Unconnected';
-                    this.onClosed && this.onClosed(this);
-
-                    // 如果重连过程中主动断开了就不再进行重连
-                    if (!this.isBrokenReconnecting) {
+                    // 判断是否当前实例
+                    // 如果连接断开后不等待 onclose 响应,由于 onclose 延迟的原因可能会在创建新的 ws 实例后触发,导致刚创建的实例被断开进入重连机制
+                    if (this.uuid === uuid) {
+                        console.warn(this.packageType, this.host, '连接已断开');
+                        this.reset();
                         this.reconnect();
                     }
                 }
@@ -177,11 +177,23 @@ export class MTP2WebSocket<T extends Package40 | Package50> {
      * 主动断开连接,断开后不会自动重连
      */
     close() {
+        console.warn(this.packageType, this.host, '主动断开');
         clearTimeout(this.reconnectTimer);
         this.stopBeatTimer();
-        this.isBrokenReconnecting = true;
+        this.uuid = v4();
         this.reconnectCount = 0;
         this.socket?.close();
+        this.reset(); // 不等待 ws.onclose 响应强制重置实例
+    }
+
+    /**
+     * 重置实例
+     */
+    private reset() {
+        this.socket = undefined;
+        this.readyState = undefined;
+        this.connState = 'Unconnected';
+        this.onClosed && this.onClosed(this);
     }
 
     /**
@@ -450,26 +462,26 @@ export class MTP2WebSocket<T extends Package40 | Package50> {
      */
     private reconnect() {
         this.stopBeatTimer();
-        if (this.isBrokenReconnecting || this.connState === 'Connecting') return;
-
-        this.reconnectCount++;
-        console.log(this.packageType, this.host, `5秒后将进行第${this.reconnectCount}次重连`);
-
-        this.reconnectTimer = window.setTimeout(() => {
-            this.readyState = undefined;
-            this.onReconnectChangeState && this.onReconnectChangeState(this, ReconnectChangeState.BeginReconnect);
-
-            this.conn().then(() => {
-                // 重连成功
-                this.reconnectCount = 0;
-                this.onReconnectChangeState && this.onReconnectChangeState(this, ReconnectChangeState.ReconnectSuccessed);
-            }).catch(() => {
-                if (!this.isBrokenReconnecting) {
-                    console.warn(this.packageType, this.host, `第${this.reconnectCount}次重连失败`);
-                    this.onReconnectChangeState && this.onReconnectChangeState(this, ReconnectChangeState.FailAndWaitPeriod);
-                }
-            })
-        }, this.reconnectInterval);
+        if (this.connState !== 'Connecting') {
+            this.reconnectCount++;
+            console.log(this.packageType, this.host, `5秒后将进行第${this.reconnectCount}次重连`);
+
+            this.reconnectTimer = window.setTimeout(() => {
+                this.readyState = undefined;
+                this.onReconnectChangeState && this.onReconnectChangeState(this, ReconnectChangeState.BeginReconnect);
+
+                this.conn().then(() => {
+                    // 重连成功
+                    this.reconnectCount = 0;
+                    this.onReconnectChangeState && this.onReconnectChangeState(this, ReconnectChangeState.ReconnectSuccessed);
+                }).catch(() => {
+                    if (this.reconnectCount) {
+                        console.warn(this.packageType, this.host, `第${this.reconnectCount}次重连失败`);
+                        this.onReconnectChangeState && this.onReconnectChangeState(this, ReconnectChangeState.FailAndWaitPeriod);
+                    }
+                })
+            }, this.reconnectInterval);
+        }
     }
 
     /**