WebSocketハートビートメカニズムとコード

9599 ワード

本文は主にwebsocket心拍数を設計する場合にどのような問題を考慮する必要があるかを述べる.
前言
Websocketを使用すると、クライアントネットワークが閉じている場合がありますが、サービス側でoncloseイベントがトリガーされません.次のようになります.
  • 余分な接続
  • サービス側はクライアントにデータを送信し続け、これらのデータは
  • を失う.
    したがって、クライアントとサービス側が正常に接続されているかどうかを検出するメカニズムが必要です.これがwebsocketのドキドキです.この名前はとても生き生きしていて、ドキドキ説明がまだ生きていて(正常な接続を維持しています)、ドキドキ説明がなくて(接続が切れています).
    解決すべき問題
    私のコードは主に以下のいくつかの問題を解決しました.
  • 接続後、毎秒1つの心拍が送信され、サーバは同じように1つの心拍を返し、サーバが停止していないことを示します.
  • 断線再接続(私たちがテストした環境はネットワーク接続を切断している)では、ネットワークを切断した後、ハートビートパケットが送信できないため、現在の時間が前回成功したハートビートから20秒を超えると、接続に問題が発生したことを示し、接続を閉じる必要があります.
  • 最初に接続を閉じるとwebsocketが再接続を試み、10秒の期間が設定されます.10秒以内に(ネットワーク接続を復元)接続できればメッセージの送受信を継続でき、接続できなければ閉鎖され、再接続されません.
  • 30秒以内にサーバメッセージ(心拍数毎秒送信)が受信されず、サーバが停止していると思ったらcloseイベントを呼び出し、3ステップ目に進みます.

  • 必要なもの
    考えが行き届かず、命名が規範化されていない.
  • タイマーws.keepAliveTimerは、心拍数を毎秒1回送信するために使用される.
  • 前回心拍数が成功した時間ws.last_health_timeおよび現在の時間let time = new Date().getTime();.
  • が接続を切断した場合(ws.close())、closeイベントが発生した後に10秒再接続する必要があるため、reconnect時間がかかります.
  • reconnectMarkに再接続されているかどうか.
  • 接続が切断された場合(ws.close())、wsオブジェクトtempWsを保存する必要があります.ws = { ...ws }でバインドが失われるイベントを発見しようとしたことがあります.
  • は、サーバが30秒以内にメッセージを返したかどうかを示す30秒のsettimeoutタイマws.receiveMessageTimerである.

  • コードセクション
    私はreactでwebsocketを使ってドキドキしました.ユーザーがログインするとwebsocket接続を確立します.reduxが使用されているため、この部分のコードはcomponentWillReceivePropsに置かれている.
    componentWillReceiveProps(nextProps) {
      if(nextProps.isLogin && !this.state.notificationSocket) { //             websocket
        let ws = new WebSocket(`${chatUrl}/${nextProps.userId}`);
        ws.last_health_time = -1; //        
        ws.keepalive = function() { 
          let time = new Date().getTime();
          if(ws.last_health_time !== -1 && time - ws.last_health_time > 20000) { //          20s
            ws.close()
          } else { 
            //      ,ws.send         。ws.bufferedAmount   0if(ws.bufferedAmount === 0 && ws.readyState === 1) { 
              ws.send('h&b');
              ws.last_health_time = time;
            }
          }
        }
        if(ws) {
          let reconnect = 0; //     
          let reconnectMark = false; //     
          this.setState({
            notificationSocket: true
          })
          ws.onopen = () => {
            reconnect = 0;
            reconnectMark = false;
            ws.receiveMessageTimer = setTimeout(() => {
              ws.close();
            }, 30000); // 30s     ,         ,    。       ,      。
            if(ws.readyState === 1) { //  1      open  
              ws.keepAliveTimer = setInterval(() => {
                ws.keepalive();
              }, 1000)
            }
    
          }
          ws.onerror = () => {
            console.error('onerror')
          }
          ws.onmessage = (msg) => {
          /*                ,      
            msg = JSON.parse(msg.data);
            let chatObj = JSON.parse(localStorage.getItem(CHATOBJECT)) || {};
            if(msg && msg.senderUserId && !chatObj[msg.senderUserId]) chatObj[msg.senderUserId] = [];
            if(msg.content !== 'h&b') {
              if(msg.chat === true) { //   
                // chatObj[msg.senderUserId] = [

    new Date().getTime()}>{msg.content}

    , ...chatObj[msg.senderUserId]] chatObj[msg.senderUserId].unshift(msg.content); WindowNotificationUtils.notice(msg.title, msg.content, () => { const { history } = this.props; history.replace({ pathname: '/sendNotice', search: `?senderUserId=${msg.senderUserId}` // url, }); }) localStorage.setItem(CHATOBJECT, JSON.stringify(chatObj)); this.props.dispatch({ type: UPDATE_CHAT }) } else { // WindowNotificationUtils.notice(msg.title, msg.content); } } */ // , clearTimeout(ws.receiveMessageTimer); ws.receiveMessageTimer = setTimeout(() => { ws.close(); }, 30000); // 30s , , 。 } ws.onclose = () => { clearTimeout(ws.receiveMessageTimer); clearInterval(ws.keepAliveTimer); if(!reconnectMark) { // , 。 reconnect = new Date().getTime(); reconnectMark = true; } let tempWs = ws; // ws if(new Date().getTime() - reconnect >= 10000) { // 10 , ws.close(); } else { ws = new WebSocket(`${chatUrl}/${nextProps.userId}`); ws.onopen = tempWs.onopen; ws.onmessage = tempWs.onmessage; ws.onerror = tempWs.onerror; ws.onclose = tempWs.onclose; ws.keepalive = tempWs.keepalive; ws.last_health_time = -1; } } } } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92