【问题标题】:NodeJS Websocket how to reconnect when server restartsNodeJS Websocket如何在服务器重新启动时重新连接
【发布时间】:2013-11-10 14:26:27
【问题描述】:

在 Node.js 中,我使用 websockets/ws 进行 WebSocket 连接。下面是客户端的代码。假设我们要连接的服务器套接字关闭了一分钟。 close 事件将触发,但是当服务器上的套接字出现故障或错误时,重新连接到套接字的最佳方法是什么?

var ws = new WebSocket('ws://localhost');

ws.on('open', function() {
    console.log('socket open');
});
ws.on('error', function() {
    console.log('socket error');
    // how do I reconnect to the ws after x minutes here?
});
ws.on('close', function() {
    console.log('socket close');
    // how do I reconnect to the ws after x minutes here?
});

【问题讨论】:

    标签: node.js websocket


    【解决方案1】:

    试试这个:

    var reconnectInterval = x * 1000 * 60;
    var ws;
    var connect = function(){
        ws = new WebSocket('ws://localhost');
        ws.on('open', function() {
            console.log('socket open');
        });
        ws.on('error', function() {
            console.log('socket error');
        });
        ws.on('close', function() {
            console.log('socket close');
            setTimeout(connect, reconnectInterval);
        });
    };
    connect();
    

    您无需包装即可使用原始实现。

    【讨论】:

    • Close 总是在出错后被调用。这将在出错时调用 connect 两次。
    • @DustinGraham 你是绝对正确的。是否会简单地删除错误回调?如果我没有及时回复,请随时自行编辑答案。
    • 最佳答案,简单无依赖
    【解决方案2】:

    我已经成功使用了https://github.com/joewalnes/reconnecting-websocket/blob/master/reconnecting-websocket.js

    你应该可以做到:

    ws = new ReconnectingWebSocket('ws://....');
    ws.reconnectInterval = 60000; // try to reconnect after 10 seconds
    

    【讨论】:

    • 有趣。我会研究一下,但我更喜欢使用 einaros 的 ws。
    • 这是一个客户端库。您仍然可以在服务器上使用 einaros 库。
    • 糟糕,我明白了。您正在从 node.js 连接到 websocket。这仍然可能有所帮助。您可以使用它来包装 einaros WebSocket。
    • 我不确定我是否理解。您将如何使用它来包装 einaros WebSocket?你能举个例子吗?
    • 将 ReconnectingWebSocket 更改为 gist.github.com/trevordixon/7239401。 (第 51 和 183 行是新的。)然后,在您的客户端代码中,使用 var WebSocket = require('./ReconnectingWebSocket.js') 而不是 require('ws'),您将使用包装在 ReconnectingWebSocket 中的 ws 库。
    【解决方案3】:

    2018 年 1 月更新

    重新连接到断开的网络套接字是non-trivial, and best delegated to a library。目前为此目的最小且维护最积极的库是reconnecting-websocket,其中obsoletes joewalnes's library来自另一个答案。具体到Node.js,需要传入一个构造函数,比如WebSocket:

    import WebSocket from 'ws';
    import ReconnectingWebSocket from 'reconnecting-websocket';
    const ws = new ReconnectingWebSocket('wss://some-feed.com', [], {
      constructor: WebSocket,
      connectionTimeout: ...,  // in milliseconds
      reconnectInterval: ...,
    });
    

    【讨论】:

      【解决方案4】:

      如果套接字关闭或服务器上发生任何错误,则使用 async-await 客户端将永远尝试每 5 秒自动连接一次

      var ws = require('ws')
      var openedSocket = null
      var timeInterval = 5000
      var port = 3000
      var url = `ws://localhost:${port}`
      
      function connect() {
        var client = new ws(url)
        return new Promise((resolve, reject) => {
          console.log('client try to connect...')
      
          client.on('open', () => {
            console.log('WEBSOCKET_OPEN: client connected to server at port %s', port)
            openedSocket = true
            resolve(openedSocket)
          })
      
          client.on('message', (data) => {
            console.log(data.toString())
          })
      
          client.on('close', (err) => {
            console.log('WEBSOCKET_CLOSE: connection closed %o', err)
            openedSocket = false
            reject(err)
          })
      
          client.on('error', (err) => {
            console.log('WEBSOCKET_ERROR: Error', new Error(err.message))
            openedSocket = false
            reject(err)
          })
        })
      }
      
      async function reconnect() {
        try {
          await connect()
        } catch (err) {
          console.log('WEBSOCKET_RECONNECT: Error', new Error(err).message)
        }
      }
      
      reconnect()
      
      // repeat every 5 seconds
      setInterval(() => {
        if (!openedSocket) {
          reconnect()
        }
      }, timeInterval)
      

      【讨论】:

      • 很好的例子,谢谢。
      【解决方案5】:

      您应该考虑迁移到socket.io

      1. 它具有内置的自动重新连接功能。而且您无需为此做任何事情。默认情况下已启用。
      2. 令人惊讶的是,它与旧版浏览器兼容,甚至是不支持本机 websocket 的浏览器。

      两者的代码非常相似,但socket.io 可能只是更短一点。例如对于我们以前编写的服务器代码,如下所示:

      const WebSocketServer = require('websocket').server
      const ws = new WebSocketServer({ httpServer });
      ws.on('request', (request) => onConnection(request));
      
      function onConnectionRequest(request) {
        const connection = request.accept(null, request.origin);
        if (!connection) return;
        connection.on('message', (msg) => onMessageReceived(msg));
        connection.on('close', () => onConnectionClosed());
      }
      
      function onMessage(message) {
        if (message.type === 'utf8') {
          const data = message.utf8Data;
          const request = JSON.parse(data);
          // todo use request
        }
      }
      

      Socket.io 代码非常相似,只是更短一些。

      const io = require('socket.io')(httpServer);
      io.on('connection', (socket) => onConnection(socket));
      
      function onConnection(socket) {
        socket.on('message', (msg) => onMessage(msg));
        socket.on('disconnect', (reason) => onDisconnect(reason));
      }
      
      function onMessage(request) {
        // todo use request
      }
      

      但是,请记住,您还必须重写客户端代码。 例如对于 Angular,我使用 ngx-socket-io 插件,它极大地简化了代码。

      【讨论】:

        【解决方案6】:

        检查@Mohamed Farouk 的回答后, 我相信用诺言来表示是有好处的 连接的状态。 这是一个从那个答案中提取一点的例子,还有一点 来自我的原文:

        const address = "ws://localhost";
        const reconnectInterval = x * 1000 * 60;
        const ws = {};
        const establishSocket = address => new Promise((resolve, reject)=>{
          const s = new WebSocket(address);
          s.on("open", ()=>{
            delete ws.reason;
            ws.socket = s;
            console.log('socket open');
          });
          s.on("error", ()=>console.log('socket error'));
          s.on("close", reject);
        }).catch(async (reason)=>{
          ws.socket = null;
          ws.reason = reason;
          console.log('socket close');
          await new Promise(resolve=>setTimeout(resolve, reconnectInterval));
          establishSocket(address);
        });
        establishSocket(address);
        

        我没有断言哪种方法更好——我只是认为这是一个有趣的解决方案。

        【讨论】:

          猜你喜欢
          • 2011-04-16
          • 2022-08-24
          • 1970-01-01
          • 2015-11-20
          • 1970-01-01
          • 1970-01-01
          • 2018-02-10
          • 2016-07-23
          • 2017-09-15
          相关资源
          最近更新 更多