// 定义 SocketService 类,用于管理 WebSocket 连接
class SocketService {
// 静态属性,用于存储单例实例
private static instance: SocketService;
// 存储 WebSocket 实例
private socket: WebSocket | null = null;
// 重连定时器
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
// 重连次数
private reconnectAttempts = 0;
// 最大重连次数
private maxReconnectAttempts = 1000;
// 重连间隔时间(毫秒)
private reconnectInterval = 3000;
// 心跳定时器
private heartbeatTimer: ReturnType<typeof setTimeout> | null = null;
// 心跳间隔时间(毫秒)
private heartbeatInterval = 5000;
// 心跳超时时间(毫秒)
private heartbeatTimeout = 10000;
// 消息处理回调函数
private messageCallback: ((data: any) => void) | null = null;
// 连接关闭标志位
private isClosed = false;
// 静态方法,用于获取 SocketService 的单例实例
public static getInstance(): SocketService {
// 如果实例还未创建,则创建一个新的实例
if (!SocketService.instance) {
SocketService.instance = new SocketService();
}
// 返回单例实例
return SocketService.instance;
}
/**
* 连接到 WebSocket 服务器
* @param url - 服务器的 WebSocket 地址
*/
connect(url: string): void {
// 若 socket 未创建,则进行创建
if (!this.socket) {
// 创建 WebSocket 实例
this.socket = new WebSocket(url);
this.isClosed = false;
// 监听连接成功事件,连接成功时打印日志
this.socket.onopen = () => {
console.log('Connected to the server');
this.reconnectAttempts = 0;
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
this.startHeartbeat();
if (this.socket) {
this.socket.onmessage = this.handleMessage.bind(this);
}
};
// 监听连接关闭事件,关闭连接时打印日志,并将 socket 置为 null
this.socket.onclose = () => {
console.log('Disconnected from the server');
this.isClosed = true;
this.stopHeartbeat();
this.socket = null;
this.reconnect(url);
};
// 监听连接错误事件,出错时打印错误信息
this.socket.onerror = error => {
console.error('Connection error:', error);
this.isClosed = true;
this.stopHeartbeat();
this.socket = null;
this.reconnect(url);
};
}
}
private reconnect(url: string) {
if (this.reconnectAttempts < this.maxReconnectAttempts && this.isClosed) {
this.reconnectAttempts++;
console.log(`正在尝试重新连接第 ${this.reconnectAttempts} 次`);
this.reconnectTimer = setTimeout(() => {
this.connect(url);
}, this.reconnectInterval);
} else {
console.log('超过最大重连次数,停止重连');
}
}
private startHeartbeat() {
this.heartbeatTimer = setTimeout(() => {
this.sendMessage('heartbeat');
this.heartbeatTimer = setTimeout(() => {
console.log('心跳超时,断开连接,准备尝试重连...');
this.stopHeartbeat();
if (this.socket) {
this.socket.close();
}
}, this.heartbeatTimeout);
}, this.heartbeatInterval);
}
private resetHeartbeat() {
if (this.heartbeatTimer) {
clearTimeout(this.heartbeatTimer);
this.startHeartbeat();
}
}
private stopHeartbeat() {
if (this.heartbeatTimer) {
clearTimeout(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
/**
* 向服务器发送消息
* @param data - 要发送的数据
*/
sendMessage(data: any): void {
// 检查 socket 是否存在且连接处于打开状态
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
console.error('Socket is not connected.');
return;
}
// 将事件名称和数据组合成对象,并序列化为 JSON 字符串
const message = JSON.stringify(data);
// 发送消息
this.socket.send(message);
}
/**
* 监听服务器发送的消息
* @param callback - 消息处理回调函数,接收事件名称和数据作为参数
*/
onMessage(callback: (data: any) => void): void {
this.messageCallback = callback;
}
private handleMessage(msgEvent: MessageEvent) {
try {
// 尝试将接收到的消息解析为 JSON 对象
const data = JSON.parse(msgEvent.data);
console.log('Received message:', data);
if (data === 'heartbeat') {
this.resetHeartbeat();
} else if (this.messageCallback) {
// 调用回调函数处理消息
this.messageCallback(data);
}
} catch (error) {
// 解析出错时打印错误信息
console.error('Error parsing message:', error);
}
}
/**
* 断开与服务器的连接
*/
disconnect(): void {
// 若 socket 存在,则关闭连接并将其置为 null
if (this.socket) {
this.isClosed = true;
this.stopHeartbeat();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
this.socket.close();
this.socket = null;
}
}
/**
* 判断当前是否与服务器连接
* @returns 如果连接则返回 true,否则返回 false
*/
isConnected(): boolean {
// 通过检查 socket 的 readyState 是否为 OPEN 来判断连接状态
return this.socket?.readyState === WebSocket.OPEN;
}
}
// 导出单例实例
export default SocketService;