一. 简单node搭建websocket服务端
下载插件
npm i nodejs-websocket --save
创建server.js文件
const ws = require("nodejs-websocket");
var _server = ws.createServer(conn => {
// 接收客户端返回的数据
conn.on("text", function(str) { //监听客户端传过来的信息
console.log(str,"接收客户端传过来的值");
//conn.sendText方法用于返回给客户端内容
conn.sendText(JSON.stringify(
{
message:value.path + str
}
));
});
//客户端关闭连接
conn.on("close", function() {
});
conn.on("error", function(err) {
//error
console.log(err, "连接报错");
});
});
// 定义端口为8000【端口自己随意定义】已经被占用的端口, 会连接不上,需要自行更换端口
const port = 8000;
_server.listen(port, function() {
console.log("连接成功")
console.log('listening on websocketServer');
})
运行server.js文件, 每当server.js文件被更改后, 都需要重新运行
node ./server.js
二. websocket封装
心跳机制: 用于长时间无信息往来情况下, 保持活性
- 1.连接服务器后开始发送心跳, 在服务端长时间无主动返回信息的情况下, 每隔10s发送一次, 间隔3s无返回则主动断线重连(判断依据是, 每当有信息返回则清空心跳定时器和延时器, 再重开心跳)
- 2.在服务器一直不间断发送信息的情况下, 每次接收到信息, 则重新计算心跳间隔, 类似防抖效果
- 3.封装主动清空心跳, 用于外部断开链接后使用
断线重连:
- 1.主动断线: 组件销毁时, 手动断线, 无需重连
- 2.被动断线: 心跳检测断线,本地网络问题, 服务端连接问题
- 3.给节流,每2s内只能执行一次
关于close与error事件的发触发
- 连接后服务端掉线, 只触发了close, 但是没有触发error
- new websocket连接不上, 会触发close以及error事件
- 网络慢造成的断线, 直接调用websocket.send会报错,此时调用websocket.close()是不会触发close事件的
完整封装websocket.js
export class WebSocketDerive {
constructor(url, heartbeatTime = 10000, callBack) {
this.url = url; //地址
this.websocket = null; // 实例
this.heartbeatTime = heartbeatTime; //心跳间隔时间,默认10s
this.heartbeatInterval = null; //心跳定时器
this.heartbeatTimeOut = null; //心跳返回判断
this.reconnect = true; //是否断线重连, 默认为true, 自动重连
this.callBack = callBack;//callBack是外部方法, 用于返回信息后调用传递信息出去
this.connect(); //初始化连接
}
// 连接
connect() {
let _this = this;
this.websocket = new WebSocket(this.url);
this.websocket.onopen = function () {
_this.startHeartbeat(); //开启心跳
};
// 返回信息处理
this.websocket.onmessage = function (e) {
let res = e.data ? JSON.parse(e.data) : null; //获取返回信息
if (res) {
_this.startHeartbeat(); //开启新心跳, 即重置心跳
// 信息处理,传到外面
_this.callBack && _this.callBack(res);
}
};
this.websocket.onerror = function () {
_this.reconnection();
console.log("连接错误");
};
this.websocket.onclose = function () {
_this.reconnection();
};
}
// 心跳
startHeartbeat() {
this.stopHeartbeat(); //重置定时器与延时器
this.heartbeatInterval = setInterval(() => {
if (this.websocket.readyState == 1) { //为open状态下才发送, 否则调用send会报错
//发送心跳信息
this.websocket.send(
JSON.stringify({
content: "ping",
})
);
}
//3s内没被重置则断线重连
this.heartbeatTimeOut = setTimeout(() => {// 作用: 1.心跳send发送后无返回重连, 2.客户端网络错误时重连
this.reconnection()
}, 3000);
}, this.heartbeatTime);
}
// 关闭心跳
stopHeartbeat() {
clearInterval(this.heartbeatInterval);
clearTimeout(this.heartbeatTimeOut);
}
//发送消息
send(message) {
message = typeof message === String ? message : JSON.stringify(message);
this.websocket.send(message);
}
//关闭连接,手动断线
close() {
this.reconnect = false;
this.stopHeartbeat();
this.websocket.close();
}
flag = false; //节流阀
// 断线重连
reconnection() {
if (!this.reconnect) return false;
if (!this.flag) {
this.flag = true;
this.stopHeartbeat();
setTimeout(() => {
this.connect();
this.flag = false;
}, 2000);
}
}
}
三. 使用
注意事项: 组件销毁时, 记得调用close方法, 否则心跳定时器没关会内存泄露
<template>
<div></div>
</template>
<script>
import {WebSocketDerive} from "../../websocket.js"
export default {
name: "HelloWorld",
props: "",
data() {
return {
websocket:null,//websocket实例
};
},
methods: {
callBack(message){
console.log(message,"接收信息")
}
},
mounted() {
this.websocket = new WebSocketDerive('ws://localhost:8000',10000,callBack)
},
destroyed(){
this.websocket.close()
}
};
</script>