In the process of using websocket, sometimes the network is disconnected, but the server does not trigger the onClose event when the network is disconnected. The server will continue to send redundant links to the client, and the data will be lost. Therefore, a mechanism is needed to detect whether the client and server are properly connected. Hence the websocket heartbeat. There’s a heartbeat, which means you’re alive, and no heartbeat means you’re dead.

1. Why is it called a heartbeat bag?

It’s like a heartbeat at regular intervals, telling the server THAT I’m still alive.

2. What is the heartbeat mechanism?

The heartbeat mechanism is a mechanism that periodically sends a custom structure (heartbeat packet) to let the other party know that they are alive and ensure the validity of the connection.

Implementation method? The following code:
class wsRequest {

	constructor(url, time) {
		this.status = null; // Whether webSocket is closed
		this.lockReconnect = false // Avoid duplicate connections
		this.url = url

		// Heartbeat detection
		this.timeout= time // How many seconds to execute the test
		this.timeoutObj= null // Check whether the server is still alive
		this.reconnectTimeOutObj= null // How long after reconnection to reconnect again

		try {
			return this.initRequest()
		} catch (e) {
			console.log('catch');
			this.reconnect(); }}initRequest() {
		this.socketTask = uni.connectSocket({
			url: this.url, // Interface address.
			success: () = > {
				console.log('Connection successful');
				// Return the instance
				return this.socketTask
			}
		})
		
		this.socketTask.onOpen(res= > {
			console.log(res, 'Connection open');
			// Clear the reconnection timer
			clearTimeout(this.reconnectTimeOutObj)
			// Enable detection
			this.start()
			
		})

		// Bind the reconnection method on close or error if you want the WebSocket connection to last forever.
		this.socketTask.onClose((res) = > {
			console.log(res, 'Connection closed');
			this.reconnect();
		})

		this.socketTask.onError((res) = > {
			console.log(res, 'Connection error');
			this.reconnect();
		})
		
		this.socketTask.onMessage(res= > {
			// Accepting any message indicates that the current connection is normal
			this.reset();
			console.log(res, 'pong'); })}send(value) {
		return new Promise((resovle,reject) = >{
			this.socketTask.send({
				data: value,
				success:() = >{
					resovle('Sent successfully')}})})}// The reset and start methods are used to control the timing of the heartbeat.
	reset(){
		// Clear the timer and re-send a heartbeat message
		clearTimeout(this.timeoutObj);this.start();
	}
	start(){
		this.timeoutObj = setTimeout(() = > {
			// A heartbeat message is sent, and the back end returns a heartbeat message,
			// if onMessage receives the returned heartbeat, the connection is normal
			console.log('ping');
			this.socketTask.send({data:"ping"});
			
		}, this.timeout)
	}

	/ / reconnection
	reconnect() {
		// Prevent multiple method calls, multiple reconnections
		if (this.lockReconnect) {
			return;
		};
		this.lockReconnect = true;
		
		console.log('Ready for reconnection');
		
		// Set delay to avoid too many requests
		this.reconnectTimeOutObj = setTimeout(() = >{
			// Reconnect
			this.initRequest()

			this.lockReconnect = false;
		}, 4000);
	}

	// Manually close
	close() {
		this.socketTask.close()
	}
}

module.exports = wsRequest

Copy the code
The specific ideas are as follows:

1. Create a wsRequest class to initialize the constructor data

class wsRequest {

	constructor(url, time) {
		this.status = null; // Whether webSocket is closed
		this.lockReconnect = false // Avoid duplicate connections
		this.url = url
	
		// Heartbeat detection
		this.timeout= time // How many seconds to execute the test
		this.timeoutObj= null // Check whether the server is still alive
		this.reconnectTimeOutObj= null // How long after reconnection to reconnect again
	
		try {
			return this.initRequest()
		} catch (e) {
			console.log('catch');
			this.reconnect(); }}}Copy the code

2. The second step is to use initRequest, which calls the websocket API of uni-App:

initRequest() {
	this.socketTask = uni.connectSocket({
		url: this.url, // Interface address.
		success: () = > {
			console.log('Connection successful');
			
			// Return the instance
			return this.socketTask
		}
	})
		
	this.socketTask.onOpen(res= > {
		console.log(res, 'Connection open');
	})

	this.socketTask.onClose((res) = > {
		console.log(res, 'Connection closed');
	})

	this.socketTask.onError((res) = > {
		console.log(res, 'Connection error');
	})
	
	this.socketTask.onMessage(res= > {
		console.log(res); })}Copy the code

2.1 Send Sends events

send(value) {
	// This return is optional
	//return new Promise((resovle,reject)=>{
		this.socketTask.send({
			data: value,
			success:() = >{
				resovle('Sent successfully')}})/ /})
}
Copy the code

3. Reconnect code is as follows:

reconnect() {
	// Prevent multiple method calls (onError/onError will be called), multiple reconnections
	if (this.lockReconnect) {
		return;
	};
	this.lockReconnect = true;
	
	console.log('Ready for reconnection');
	
	// Set delay to avoid too many requests
	this.reconnectTimeOutObj = setTimeout(() = >{
		// Reconnect
		this.initRequest()
		this.lockReconnect = false;
	}, 5000);
}
Copy the code

Call reconnect in the onClose,onError listener event

4. Detect heartbeat and send heartbeat packets

reset(){
	// Clear the timer and re-send a heartbeat message
	clearTimeout(this.timeoutObj);this.start();
}
start(){
	this.timeoutObj = setTimeout(() = > {
		// A heartbeat message is sent, and the back end returns a heartbeat message,
		// if onMessage receives the returned heartbeat, the connection is normal
		console.log('ping');
		this.socketTask.send({data:"ping"});
		
	}, this.timeout)
}
Copy the code

Enable detection when the onOpen link is opened and reset the timer when the onMessage listener receives a message

this.socketTask.onOpen(res= > {
	console.log(res, 'Connection open');
	
	// Clear the reconnection timer
	clearTimeout(this.reconnectTimeOutObj)
	
	// Enable detection
	this.start()
	
})

this.socketTask.onMessage(res= > {
	// Accepting any message indicates that the current connection is normal
	this.reset();
	console.log(res, 'pong');
})
Copy the code

The idea of heartbeat detection is as follows: Fixed time intervals and send a ping to a server-side data, if in normal circumstances, the server will return a pong to the client, if the client through the onMessage event can listen to the words, that request is normal, here using a timer, under the condition of every 5 seconds, if it is under the condition of network disconnection, The server does not return a heartbeat response message within the specified time, so the server is disconnected, so this time is heard through the onClose event. So inside the onClose event, we can call the Reconnect event to do the reconnect.