🕸️

ReconnectingWebSocket を使った WebSocket 自動再接続実装

に公開

Reconnecting WebSocket の導入・設定・実装・テストまとめ

WebSocketは標準APIに自動再接続機能がありません。
ReconnectingWebSocketを使うことで、接続が切れた場合も自動で再接続する仕組みを簡単に追加できます

1. インストール

npm install reconnecting-websocket
# または
yarn add reconnecting-websocket

2. 基本設定

例:

import ReconnectingWebSocket from 'reconnecting-websocket';

// 接続が切れた場合、自動で再接続を試みる
const wsc = new ReconnectingWebSocket('ws://localhost:8080');

// サーバーへの接続が確立したときに呼ばれる
wsc.onopen = () => {
  console.log('接続成功');
};

// サーバーからデータが送られてきたときに呼ばれる
wsc.onmessage = (event) => {
  console.log('受信:', event.data);
};

// ネットワークエラーや接続問題が発生した場合に呼ばれる
wsc.onerror = (error) => {
  console.error('エラー:', error);
};

// 接続が閉じられた場合に呼ばれる
wsc.onclose = () => {
  console.log('切断。再接続を試みます');
};

3. オプション設定

例:

import WS from 'ws'; // Node.jsの場合

const options = {
  WebSocket: WS, // Node.jsでは指定必須。指定されていない場合、デフォルトでglobal.WebSocketが使用されます。  
  maxReconnectionDelay: 10000,  // 最大遅延
  minReconnectionDelay: 1000,   // 最小遅延
  reconnectionDelayGrowFactor: 1.3, // 再接続遅延の増加率
  connectionTimeout: 4000,      // 接続タイムアウト
  maxRetries: Infinity,         // リトライ最大回数
  debug: true                   // デバッグログ
};

const ws = new ReconnectingWebSocket('ws://localhost:8080', [], options);

4. Ping/Pong で生存確認

WebSocketには readyState という、今の接続状態を表す数字があります。OPEN なら「接続中」、CLOSED なら「切断」という意味です(詳しくはこちら)。

でも、PCがスリープしたり、ネットがちょっと途切れたりすると、この状態がズレることがあるようです。つまり、「つながってるはずなのに、実は通信できてない」というパターンです。

そこで、10秒ごとにサーバーに「ping」ってメッセージを送って、すぐに「pong」って返事が来なかったら再接続するようにします。

クライアント側

// 最後のPONG受信時間
wsc.lastPong = Date.now();

// 接続状態チェック用
wsc.isConnecting = () => {
  return wsc.readyState === WebSocket.CONNECTING || wsc.readyState === WebSocket.OPEN;
};

// Ping/Pongで生存確認
wsc.startPing = function(interval = 10000) {
  // 既にPingループが存在する場合は二重起動を防止
  if (this.pingInterval) return;
  // 定期実行(10秒毎にサーバーへ ping を送信)
  this.pingInterval = setInterval(() => {
    // 接続中であれば ping を送信
    if (this.isConnecting()) {
      const now = Date.now();
      this.send(JSON.stringify({ action: 'ping' }));
      // 最後に pong を受信してから10秒以上経過していたら再接続
      if (now - this.lastPong > interval) {
        console.warn("PONG応答なし。再接続を試みます。");
        this.close(); // ReconnectingWebSocketが自動で再接続
      }
    }
  }, interval);
};

// PingPongループを停止する
wsc.stopPing = function() {
  if (this.pingInterval) {
    clearInterval(this.pingInterval);
    this.pingInterval = null; // 状態リセット
  }
};

// 接続通知
wsc.onopen = () => {
  console.log('接続成功');
  // lastPong を初期化
  wsc.lastPong = Date.now();
  // PingPongを開始
  wsc.startPing();
};

// 切断
wsc.onclose = () => {
  console.log( 'connection.onclose' )
  console.log('切断');
  // PingPongを停止
  wsc.stopPing();
};

// メッセージ受信
wsc.onmessage = (event) => {
  try {
    console.log( 'connection.onmessage' )
    const data = JSON.parse(event.data);
    console.log(data)
    // action: "pong" の場合 → lastPong を更新
    if (data.action === 'pong') {
      wsc.lastPong = Date.now();
      console.log('lastPong更新:', wsc.lastPong);
    } else {
      console.log('受信:', data);
    }
  } catch {
    console.log('受信:', event.data);
  }
};

サーバ側(Node.js)

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

// クライアントが接続してきたときに呼ばれる
wss.on('connection', (ws) => {
  ws.on('message', (message) => {
    try {
      const data = JSON.parse(message);

      // サーバー側のPing/Pong処理
      if (data.action === 'ping') {
        ws.send(JSON.stringify({ action: 'pong' }));
        return;
      }
      // 他のメッセージ処理
    } catch {
      console.log('受信:', message);
    }
  });
});

5. 動作確認

ちゃんと動くかテストしてみます。

  1. サーバーを起動
  2. クライアントを接続
  3. ping / pong で接続維持できているか確認
  4. サーバーを一時停止
  5. クライアントが自動で再接続するか確認

確認結果

まとめ

  • ReconnectingWebSocket を使うと、WebSocketに自動再接続機能を簡単に追加可能です
  • オプションで再接続の待ち時間とかリトライ回数を調整できます

参考

ファースト・スクラッチTech Blog

Discussion