Browse Source

修改ws

master
liaoxinyu 1 month ago
parent
commit
bbe4c2a637
  1. 344
      src/api/server/Socket.js
  2. 3
      src/views/contract/handicap.vue

344
src/api/server/Socket.js

@ -1,52 +1,216 @@
// class Socket {
// constructor(link, ...args) {
// // 初始化socket
// if (link.constructor === WebSocket) {
// this.socket = link;
// } else {
// this.socket = new WebSocket(link);
// }
// // this.socket.binaryType = 'arraybuffer';
// this.doOpen();
// // 连接状态的标识符
// this.readyState = this.socket.readyState;
// // 订阅/发布模型
// this._events = {
// // 订阅的事件 : 发布的方法
// };
// // 定时验证的标识符
// this.heartBeatTimer = null;
// }
// // 执行socket并发布事件
// doOpen() {
// this.afterOpenEmit = [];
// // 执行socket连接 并初始化验证请求
// this.socket.addEventListener("open", evt => this.onOpen(evt));
// // 接收socket数据
// this.socket.addEventListener("message", evt => this.onMessage(evt));
// // 关闭socket连接
// this.socket.addEventListener("close", evt => this.onClose(evt));
// // 请求发生错误
// this.socket.addEventListener("error", err => this.onError(err));
// }
// // 发布后通知订阅者
// Notify(entry) {
// // 检查是否有订阅者 返回队列
// const cbQueue = this._events[entry.Event];
// if (cbQueue && cbQueue.length) {
// for (let callback of cbQueue) {
// if (callback instanceof Function) callback(entry.Data);
// }
// }
// }
// // 请求数据的方法
// onOpen(evt) {
// // 每隔20s检查连接
// // this.heartBeatTimer = setInterval(() => this.send({
// // 'cmd': 'ping',
// // 'args': ''
// // }), 20000);
// // 通知订阅
// this.Notify({Event: 'open', Data : evt});
// }
// /**
// * 订阅所有的数据
// * @param {array|object} datas 订阅参数集合
// */
// send(datas) {
// if (datas.constructor != Array) {
// datas = [datas];
// }
// for (let item of datas) {
// this.socket.send(JSON.stringify(item));
// }
// }
// onMessage(evt) {
// try {
// // 解析推送的数据
// const data = JSON.parse(evt.data);
// // 通知订阅者
// this.Notify({
// Event: 'message',
// Data: data
// });
// } catch (err) {
// console.error(' >> Data parsing error:', err);
// // 通知订阅者
// this.Notify({
// Event: 'error',
// Data: err
// });
// }
// }
// // 添加事件监听
// on(name, handler) {
// this.subscribe(name, handler);
// }
// // 取消订阅事件
// off(name, handler) {
// this.unsubscribe(name, handler);
// }
// // 订阅事件的方法
// subscribe(name, handler) {
// if (this._events.hasOwnProperty(name)) {
// this._events[name].push(handler); // 追加事件
// } else {
// this._events[name] = [handler]; // 添加事件
// }
// }
// // 取消订阅事件
// unsubscribe(name, handler) {
// let start = this._events[name].findIndex(item => item === handler);
// // 删除该事件
// this._events[name].splice(start, 1);
// }
// checkOpen() {
// return this.readyState >= 2;
// }
// onClose(evt) {
// this.Notify({Event: 'close', Data : evt});
// }
// onError(err) {
// this.Notify({Event: 'error', Data : err});
// }
// emit(data) {
// return new Promise((resolve) => {
// this.send(JSON.stringify(data));
// this.on('message', function (data) {
// resolve(data);
// });
// });
// }
// doClose() {
// this.socket.close();
// }
// destroy() {
// if (this.heartBeatTimer) {
// clearInterval(this.heartBeatTimer);
// this.heartBeatTimer = null;
// }
// this.doClose();
// this._events = {};
// this.readyState = 0;
// this.socket = null;
// }
// }
// export default Socket
class Socket { class Socket {
constructor(link, ...args) { constructor(link, ...args) {
// 初始化socket // ✅ 修复1:确保 this.link 存的是字符串,方便后面断线重连
if (link.constructor === WebSocket) { if (link.constructor === WebSocket) {
this.socket = link; this.socket = link;
this.link = link.url;
} else { } else {
this.socket = new WebSocket(link); this.socket = new WebSocket(link);
this.link = link;
} }
// this.socket.binaryType = 'arraybuffer';
this.doOpen(); this.doOpen();
// 连接状态的标识符
this.readyState = this.socket.readyState; this.readyState = this.socket.readyState;
// 订阅/发布模型 this._events = {};
this._events = {
// 订阅的事件 : 发布的方法
};
// 定时验证的标识符
this.heartBeatTimer = null; this.heartBeatTimer = null;
// ✅ 新增:重连相关的标识符
this.reconnectTimer = null;
this.isReconnecting = false;
this.manualClose = false; // 判断是否是用户主动退出页面
} }
// 执行socket并发布事件
doOpen() { doOpen() {
this.afterOpenEmit = []; this.afterOpenEmit = [];
// 执行socket连接 并初始化验证请求
this.socket.addEventListener("open", evt => this.onOpen(evt)); this.socket.addEventListener("open", evt => this.onOpen(evt));
// 接收socket数据
this.socket.addEventListener("message", evt => this.onMessage(evt)); this.socket.addEventListener("message", evt => this.onMessage(evt));
// 关闭socket连接
this.socket.addEventListener("close", evt => this.onClose(evt)); this.socket.addEventListener("close", evt => this.onClose(evt));
// 请求发生错误
this.socket.addEventListener("error", err => this.onError(err)); this.socket.addEventListener("error", err => this.onError(err));
} }
// 发布后通知订阅者
Notify(entry) { Notify(entry) {
// 检查是否有订阅者 返回队列
const cbQueue = this._events[entry.Event]; const cbQueue = this._events[entry.Event];
if (cbQueue && cbQueue.length) { if (cbQueue && cbQueue.length) {
for (let callback of cbQueue) { for (let callback of cbQueue) {
@ -55,118 +219,152 @@ class Socket {
} }
} }
// 请求数据的方法
onOpen(evt) { onOpen(evt) {
// 连接成功,重置状态
this.isReconnecting = false;
this.manualClose = false;
// 每次连上先清空旧的心跳,防止重复
if (this.heartBeatTimer) clearInterval(this.heartBeatTimer);
// 每隔20s发送心跳
this.heartBeatTimer = setInterval(() => {
this.send({
'cmd': 'ping',
'args': ''
});
}, 20000);
// 每隔20s检查连接
// this.heartBeatTimer = setInterval(() => this.send({
// 'cmd': 'ping',
// 'args': ''
// }), 20000);
// 通知订阅
this.Notify({Event: 'open', Data : evt}); this.Notify({Event: 'open', Data : evt});
} }
/**
* 订阅所有的数据
* @param {array|object} datas 订阅参数集合
*/
send(datas) { send(datas) {
if (datas.constructor != Array) { if (datas.constructor != Array) {
datas = [datas]; datas = [datas];
} }
for (let item of datas) { for (let item of datas) {
this.socket.send(JSON.stringify(item)); // ✅ 修复2:发送前必须检查状态,彻底解决 "CLOSING or CLOSED state" 报错!
if (this.socket && this.socket.readyState === 1) {
this.socket.send(JSON.stringify(item));
} else {
console.warn("WebSocket未连接,已拦截发送请求");
}
} }
} }
onMessage(evt) { onMessage(evt) {
try { try {
// 解析推送的数据
const data = JSON.parse(evt.data); const data = JSON.parse(evt.data);
this.Notify({ Event: 'message', Data: data });
// 通知订阅者
this.Notify({
Event: 'message',
Data: data
});
} catch (err) { } catch (err) {
console.error(' >> Data parsing error:', err); console.error(' >> Data parsing error:', err);
this.Notify({ Event: 'error', Data: err });
// 通知订阅者
this.Notify({
Event: 'error',
Data: err
});
} }
} }
// 添加事件监听
on(name, handler) { on(name, handler) {
this.subscribe(name, handler); this.subscribe(name, handler);
} }
// 取消订阅事件
off(name, handler) { off(name, handler) {
this.unsubscribe(name, handler); this.unsubscribe(name, handler);
} }
// 订阅事件的方法
subscribe(name, handler) { subscribe(name, handler) {
if (this._events.hasOwnProperty(name)) { if (this._events.hasOwnProperty(name)) {
this._events[name].push(handler); // 追加事件 this._events[name].push(handler);
} else { } else {
this._events[name] = [handler]; // 添加事件 this._events[name] = [handler];
} }
} }
// 取消订阅事件
unsubscribe(name, handler) { unsubscribe(name, handler) {
if (!this._events[name]) return;
let start = this._events[name].findIndex(item => item === handler); let start = this._events[name].findIndex(item => item === handler);
if (start > -1) {
// 删除该事件 this._events[name].splice(start, 1);
this._events[name].splice(start, 1); }
} }
checkOpen() { checkOpen() {
return this.readyState >= 2; return this.readyState >= 2;
} }
// ✅ 修复3:核心重连逻辑
reconnect() {
// 如果是手动关闭(退出页面),或者正在重连中,则放弃重连
if (this.manualClose || this.isReconnecting) return;
this.isReconnecting = true;
// 断网了,立刻停止发心跳
if (this.heartBeatTimer) {
clearInterval(this.heartBeatTimer);
this.heartBeatTimer = null;
}
console.log("WebSocket 掉线,3秒后尝试重新连接...");
this.reconnectTimer = setTimeout(() => {
try {
this.socket = new WebSocket(this.link);
this.doOpen();
} catch (e) {
console.error("重连失败", e);
// 即使抛出异常也解除锁,等待下一次重连尝试
this.isReconnecting = false;
this.reconnect();
return;
}
}, 3000);
}
onClose(evt) { onClose(evt) {
this.Notify({Event: 'close', Data : evt}); this.Notify({Event: 'close', Data : evt});
// 触发关闭时,只要不是主动退出的,就去重连
if (!this.manualClose) this.reconnect();
} }
onError(err) { onError(err) {
this.Notify({Event: 'error', Data : err}); this.Notify({Event: 'error', Data : err});
// 发生错误断开时,去重连
if (!this.manualClose) this.reconnect();
} }
// ✅ 修复4:解决内存泄漏,用完立刻注销
emit(data) { emit(data) {
return new Promise((resolve) => { return new Promise((resolve) => {
this.send(JSON.stringify(data)); this.send(JSON.stringify(data));
this.on('message', function (data) {
resolve(data); const handler = (resData) => {
}); resolve(resData);
this.off('message', handler); // 立刻注销,释放内存
};
this.on('message', handler);
}); });
} }
doClose() { doClose() {
this.socket.close(); this.manualClose = true; // 标记为主动关闭,防止变成僵尸无限重连
if (this.socket) {
this.socket.close();
}
} }
destroy() { destroy() {
this.manualClose = true;
if (this.heartBeatTimer) { if (this.heartBeatTimer) {
clearInterval(this.heartBeatTimer); clearInterval(this.heartBeatTimer);
this.heartBeatTimer = null; this.heartBeatTimer = null;
} }
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
this.doClose(); this.doClose();
this._events = {}; this._events = {};
this.readyState = 0; this.readyState = 0;
@ -174,4 +372,4 @@ class Socket {
} }
} }
export default Socket export default Socket;

3
src/views/contract/handicap.vue

@ -213,6 +213,9 @@ export default {
// this.$emit("input", this.newPriceObj); // this.$emit("input", this.newPriceObj);
}); });
}, },
beforeDestroy() {
this.unLink(this.symbol);
},
// //
methods: { methods: {
parseTime: date.parseTime, parseTime: date.parseTime,

Loading…
Cancel
Save