127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
export default class WebSocketWithHeartbeatAndReconnect {
|
|
private url: string
|
|
private socket: WebSocket | null
|
|
private heartbeatInterval: number
|
|
private pingMessage: string
|
|
private pongMessage: string
|
|
private reconnectInterval: number
|
|
private maxReconnectAttempts: number
|
|
private reconnectAttempts: number
|
|
private heartbeatTimer: any
|
|
private reconnectTimer: any
|
|
|
|
constructor(url: string, options = {} as any) {
|
|
this.url = url
|
|
this.socket = null
|
|
this.heartbeatInterval = options.heartbeatInterval || 30000 // 默认每 30 秒发送一次心跳
|
|
this.pingMessage = options.pingMessage || 'ping' // 默认 ping 消息
|
|
this.pongMessage = options.pongMessage || 'pong' // 默认 pong 消息
|
|
this.reconnectInterval = options.reconnectInterval || 5000 // 默认每 5 秒尝试重连
|
|
this.maxReconnectAttempts = options.maxReconnectAttempts || 5 // 最大重连次数
|
|
this.reconnectAttempts = 0 // 当前已尝试的重连次数
|
|
this.heartbeatTimer = null // 存储心跳定时器
|
|
this.reconnectTimer = null // 存储重连定时器
|
|
}
|
|
|
|
// 初始化 WebSocket 连接
|
|
connect() {
|
|
if (this.socket) {
|
|
this.socket.close() // 关闭现有连接
|
|
}
|
|
|
|
this.socket = new WebSocket(this.url)
|
|
|
|
// 连接成功时启动心跳
|
|
this.socket.onopen = () => {
|
|
console.log('WebSocket connected')
|
|
this.reconnectAttempts = 0 // 重置重连次数
|
|
this.startHeartbeat() // 启动心跳机制
|
|
}
|
|
|
|
// 接收到消息时
|
|
this.socket.onmessage = (event) => {
|
|
console.log('Received message:', event.data)
|
|
|
|
// 如果接收到 pong 消息,说明服务器回应了心跳
|
|
if (event.data === this.pongMessage) {
|
|
console.log('Pong received')
|
|
this.resetHeartbeat() // 重置心跳定时器
|
|
} else {
|
|
this.getMsg(event.data)
|
|
}
|
|
}
|
|
|
|
// 连接关闭时
|
|
this.socket.onclose = (event) => {
|
|
console.log('WebSocket closed:', event)
|
|
this.stopHeartbeat() // 停止心跳机制
|
|
this.handleReconnect() // 尝试重连
|
|
}
|
|
|
|
// 错误处理
|
|
this.socket.onerror = (error) => {
|
|
console.error('WebSocket error:', error)
|
|
this.socket?.close() // 在发生错误时关闭连接
|
|
}
|
|
}
|
|
|
|
// 启动心跳机制,定时发送 ping 消息
|
|
startHeartbeat() {
|
|
this.heartbeatTimer = setInterval(() => {
|
|
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
console.log('Sending ping...')
|
|
this.socket.send(this.pingMessage) // 发送 ping 消息
|
|
}
|
|
}, this.heartbeatInterval)
|
|
}
|
|
|
|
// 重置心跳机制
|
|
resetHeartbeat() {
|
|
clearInterval(this.heartbeatTimer) // 清除之前的心跳定时器
|
|
this.startHeartbeat() // 重新启动心跳定时器
|
|
}
|
|
|
|
// 停止心跳机制
|
|
stopHeartbeat() {
|
|
clearInterval(this.heartbeatTimer) // 清除心跳定时器
|
|
clearTimeout(this.reconnectTimer) // 清除重连定时器
|
|
}
|
|
|
|
// 处理重连机制
|
|
handleReconnect() {
|
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
this.reconnectAttempts++
|
|
console.log(`Attempting to reconnect... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`)
|
|
|
|
// 重连时延
|
|
this.reconnectTimer = setTimeout(() => {
|
|
this.connect() // 尝试重新连接
|
|
}, this.reconnectInterval)
|
|
} else {
|
|
console.log('Max reconnect attempts reached. Giving up.')
|
|
}
|
|
}
|
|
|
|
// 发送数据
|
|
send(message: string) {
|
|
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
this.socket.send(message)
|
|
console.log('Message sent:', message)
|
|
} else {
|
|
console.log('WebSocket is not open. Cannot send message.')
|
|
}
|
|
}
|
|
|
|
// 关闭连接
|
|
close() {
|
|
if (this.socket) {
|
|
this.socket.close()
|
|
console.log('WebSocket closed manually.')
|
|
}
|
|
}
|
|
// 接受到的数据
|
|
getMsg(val: string) {
|
|
console.log(val)
|
|
}
|
|
}
|