WebSocketのハートビート再接続メカニズムと、エンドロックスクリーンを移動したり、バックグラウンドで実行したりするときの再接続メカニズムの理解

8869 ワード

WebSocket心拍数再接続メカニズム
Websocketを使用する過程で、ネットワークが切断される場合がありますが、ネットワークが切断されるとサーバ側はoncloseのイベントをトリガーしません.これにより、サーバはクライアントに余分なリンクを送信し続け、これらのデータは失われます.したがって、クライアントとサービス側が正常なリンク状態にあるかどうかを検出するメカニズムが必要です.だからwebsocketのドキドキがありました.まだドキドキして、まだ生きていることを説明して、ドキドキしていない説明はもう切れました.
1.なぜハートビートバッグと呼ぶのですか?それは心臓の鼓動のように一定の時間ごとに送って、サーバーに教えて、私はまだ生きています.
2.心拍数のメカニズムは?ハートビートメカニズムは、一定時間ごとにサーバにパケットを送信し、サーバ自身が生きていることを伝えるとともに、クライアントはサーバ側が生きているかどうかを確認し、生きているとクライアントにパケットを返信してサーバ側も生きていることを確認します.そうしないと、ネットワークが切断されている可能性があります.再接続が必要です~
フロントコード:
var websocket;

//      
var serverPort = '8080';

//     
var url = '/platform-framework/api/osWebsocket';

//   IP  
function getWebIP() {
    var curIP = window.location.hostname;
    return curIP;
}


function init(){

    //ws  
    var wsuri = "ws://" + getWebIP() + ":" + serverPort + url;
    try {
        websocket = new WebSocket(wsuri);
    } catch (e) {
        console.log('            webSocket ');
    }

    websocket.onclose = function (e) {
        websocket.close();
        console.log("WebSocket   ");
    }
    
    websocket.onopen = function () {
        //      
    	heartCheck.start();
    }

    //           
    websocket.onerror = function () {
        websocket.close();
        console.log("WebSocket       ");
    }

}

//    
init();

/***
 *	webSocket       
 *         ,           
 *      (messageCallback)  ,       (websocket      )
 */
function onMessage(messageCallback) { 
    websocket.onmessage = function (e) {
        if (typeof(messageCallback) === 'function') {
            messageCallback(JSON.parse(e.data));
        }
        //       
        heartCheck.reset();
    }
}

// webSocket       
function sendSockTable(agentData) {
	if (websocket.readyState === websocket.OPEN) {
        //  ws    
        websocketsend(agentData)
    } else if (websocket.readyState === websocket.CONNECTING) {
        //          ,   1s     
        setTimeout(function () {
            sendSockTable(agentData);
        }, 1000);
    } else {
        //      ,   1s     
        setTimeout(function () {
            sendSockTable(agentData);
        }, 1000);
    }
}

//     
function websocketsend(agentData) {
    websocket.send(JSON.stringify(agentData));
}

// webSocket   
function webSocketClose() {
	websocket.close();
}

// webSocket    
function webSocketInit() {
	init();
}

//        
function webSocketRestart() {
    websocket.close();
    init();
}

//            websocket.close(),      
window.onunload = function() {
   websocket.close();
}

//        60             
var heartCheck = {
  timeout: 60000,
  timeoutObj: null,
  reset: function(){
    clearTimeout(this.timeoutObj);
    this.start();
  },
  start: function(){
    this.timeoutObj = setTimeout(function () {
      console.info("       :" + new Date());
      websocket.send('      ');
    }, this.timeout)
  }
}

export default { onMessage,sendSockTable, webSocketRestart, webSocketClose, webSocketInit}

具体的な考え方は以下の通りです.
1.最初のページを初期化し、現在のjsを呼び出すと、init()関数が自動的に呼び出され、websocketのメソッドを作成し、websocketのいくつかのメソッドを初期化することを目的とします.
2.第2ステップはonMessage(response)=>{})関数を呼び出し、webSocket自動プッシュメッセージを取得する.sendSockTable(データ)関数を呼び出し、メッセージを送信し、webSocketRestart()関数を呼び出し、webSocketを再起動します.
3.以上のように、ネットワークが切断されると、onerrorが呼び出され、oncloseイベントが傍受され、対応する操作が行われます.通常、onopenメソッドは先に呼び出され、データが受信されるとonmessageイベントによって傍受されます.
4.最後のステップは心拍検出を実現するコード
バックグラウンドコード:
package com.platform.api;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

//import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import com.platform.entity.OsOrderInfoVo;
import com.platform.entity.OsTableManagement;
import com.platform.entity.OsWebSocketVo;
import com.platform.service.OsOrderService;
import com.platform.service.OsTableManagementService;
import com.platform.util.ApplicationContextRegister;
import com.platform.util.ServerEncoder;

/**
 * @ServerEndpoint            ,                 websocket    ,
 *                    URL  ,         URL    WebSocket    
 */
@Component
@ServerEndpoint(value = "/api/websocket", encoders = { ServerEncoder.class })
public class OsWebSocketController {

	private Logger log = Logger.getLogger(OsWebSocketController.class);
	
	//    ,           。            。
	private static int onlineCount = 0;

	//concurrent      Set,            MyWebSocket  。                 ,    Map   ,  Key       
	private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();
	
	private static Map> map = new HashMap>();

	//           ,              
	private Session session;
	
	/**
	 *            a
	 * @param session       。session            ,              
	 * @throws IOException  
	 */
	@OnOpen
	public void onOpen(Session session) throws IOException{
		this.session = session;
		webSocketSet.add(this);
		addOnlineCount(); 
		log.info("OsWebSocketController ->       !       " + getOnlineCount());
	}

	/**
	 *          
	 */
	@OnClose
	public void onClose(){
		webSocketSet.remove(this);
		subOnlineCount();
		log.info("OsWebSocketController ->       !       " + getOnlineCount());
	}

	/**
	 *              
	 * @param message           
	 * @param session      
	 */
	@OnMessage
	public void onMessage(String message, Session session) {

        /***
         *                
         *        websocket ,             ,      ,
         *            ,     
         */   
		log.info("【WebSocket  】    :{}"+ message);
		if("      ".equals(message)) {
			
		} else {
			//     
            // OsWebSocketGoods vo = JSONObject.parseObject(message, OsWebSocketGoods.class);
		}
		
		//    
		for(OsWebSocketController item: webSocketSet){
			try {
				item.sendMessageTo(map);
			} catch (IOException e) {
				e.printStackTrace();
				continue;
			} catch (EncodeException e) {
				e.printStackTrace();
				continue;
			}
		}
	}
	
	/**
	 *        
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error){
		log.info("OsWebSocketController ->     !");
		log.info("OsWebSocketController ->     :" + error.getMessage());
		error.printStackTrace();
	}

	/**
	 *               。     ,            。
	 * @param message
	 * @throws IOException
	 */
	public void sendMessage(String message) throws IOException{
		this.session.getBasicRemote().sendText(message);
	}
	
	public void sendMessageTo(Map> map) throws IOException, EncodeException {
		this.session.getBasicRemote().sendObject(map);
	}

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		OsWebSocketController.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		OsWebSocketController.onlineCount--;
	}
	
	
}

心拍検出を実現する考え方は、一定時間ごとにサーバ側にpingデータを送信し、正常な場合、サーバはクライアントにpongを返し、クライアントがonmessageイベントで傍受できる場合、要求が正常であることを示し、ここではタイマを使用し、3秒ごとに(時間カスタマイズ)場合、ネットワークが切断する場合、指定された時間内にサーバ側が心拍応答メッセージを返さないため、サーバ側が切断するので、このときwebsocketを使用する.closeは接続を閉じ、しばらくしてから(異なるブラウザでは時間が異なり、firefoxの応答が速くなります)、oncloseイベントで傍受できます.したがってoncloseイベントではreconnectイベントを呼び出して再接続操作を行うことができます.
2 WebSocketモバイルエンドロックおよびバックグラウンドへの再接続メカニズム
jsは携帯電話の消灯後に中断し、起動後もjsは実行を継続します.そのためjsに設定されたタイミングでハートビートパケットを送信する機能は、携帯電話が画面を消した後では実行できません.スクリーンを消す時間が長すぎると、この時点でリンクがサービス側に強制的に切断され、ほとんどの携帯電話がスクリーンを消すとwebsocket接続が切断されます.
解決策:H 5で提供されるページを使用してAPIを非表示/表示します.

document.addEventListener('visibilitychange',function() {
	if(document.visibilityState == 'hidden') {
		//        
		let hiddenTime = new Date().getTime()	
	} else {
		let visibleTime = new Date().getTime();
		//         -    >10S,  	
		if((visibleTime - hiddenTime) / 1000 > 10){	
			//       
			WebSockets.webSocketClose();
			// 1.5S            ,         
			setTimeout(function(){
				WebSockets.openSocket()   
			},1500);    
		}else{
 			console.log('         ')
		}
	}
}

この方法は、スクリーンを消して再接続するだけでなく、携帯電話のブラウザがバックグラウンドに切り替えられたときにjsが中断する場合にも適用されます.