JavaScript部分
<script>
export default {
data() {
return {
Ws: null, //用于接收websocket实例
connctState: false, //连接状态
pingpong: null, //心跳检测定时器变量
pongCount: 0, //超时次数
maxPongCount: 5, //最大超时次数,超出后执行重新连接
}
},
mounted() {
//初始化websocket
this.init()
},
method: {
init() {
if(this.Ws) {
//已存在连接
return
}
//创建websocket实例
this.Ws = new WebSocket(`ws://locolhost:8000?userId=${userId}`)
//将四个钩子函数open(连接)/close(断开)/message(消息接收)/error(错误),添加到实例Ws上
this.Ws.addEventListener('open', this.handleOpen.bind(this), false)
this.Ws.addEventListener('close', this.handleClose.bind(this), false)
this.Ws.addEventListener('message', this.handleMessage.bind(this), false)
this.Ws.addEventListener('error', this.handleError.bind(this), false)
},
handleOpen() {
console.log('ws open')
const self = this
self.connctState = true
//创建心跳机制检测
self.pingpong = setInterval(() => {
this.Ws.send(JSON.stringify({
userId,
action: 'ping' //做为心跳检测辨识
}))
self.pongCount++ //超时次数+1
if(self.pongCount > self.maxPongCount) {
self.stopPong()
self.reconnect()
}
}, 30000)
},
handleClose() {
//连接状态修改为false
this.connctState = false
//停止心跳检测
this.stopConnect()
//尝试重连
this.reconnect()
},
handleMessage(e) {
//客户端接收到消息,触发message钩子函数
console.log(e)
const data = JSON.parse(e.data)
if(data.action === 'pong') {
//心跳机制检测标识,正常返回,超时次数重置
this.pongCount = 0
} else {
//否则处理消息
}
},
handleError() {
console.log('ws error')
},
sendMessage() {
//通过send方法将需要发送的消息传给后端,由后端发送给接收者
this.Ws.send(
JSON.stringify({
userId, //发送者ID
targetUserId, //接收者ID
message //需要发送的消息
})
)
},
onClickClose() {
//正常关闭,将实例赋值为null,并执行close钩子函数
this.Ws = null
this.handleClose()
}
stopConnect() {
//停止心跳检测
this.pongCount = 0
clearInterval(this.pingpong)
},
reconnect() {
if(this.connctState) { //连接状态为true时正常,直接返回
return
} else if(this.Ws) { //ws实例有值,重连
this.handleOpen()
}
}
}
}
</script>
node部分
//引入ws模块
const Ws = require('ws')
//创建一个立即执行函数,并将Ws传入
((Ws) => {
//创建ws服务实例,并设置端口号
const Server = new Ws.Server({ port: 8000 })
//初始化ws服务
const init = () => {
Server.on('open', handleOpen)
Server.on('close', handleClose)
Server.on('error', handleError)
Server.on('connection', handleConnection)
}
function handleOpen() {
console.log('ws server open')
}
function handleClose() {
console.log('ws server close')
}
function handleError() {
console.log('ws server error')
}
function handleConnection(data, req) {
//获取用户ID参数
console.log(req.url)
//连接成功时,会生成一个唯一的标识ws._socket.remotePort
//将用户ID和连接标识存储
console.log('唯一标识:'+ ws._socket.remotePort)
//绑定message事件
ws.on('message', handleMessage)
}
fuction handleMessage(data) {
data = JSON.parse(data)
if(data.action === 'ping') { //心跳检测机制标识
//遍历所有连接,定向发送消息
Server.clients.forEach(c => {
// c._socket._peername.port 为用户连接唯一标识,用于判断是否向该用户发送消息
// 使用c.send() 方法向用户发送消息
if(c._socket._peername.port === userPort) {
c.send(JSON.stringify({
action: 'pong'
}))
}
})
} else {
//否则获取目标用户,向目标用户发送消息
//查询targetUserId对应的连接标识,遍历判断是否发送
Server.clients.forEach(c => {
if(c._socket._peername.port === targetUserPort) {
c.send(JSON.stringify({
msg: data.msg
}))
}
})
}
}
init()
})(Ws)