【问题标题】:WebSocket: How to automatically reconnect after it diesWebSocket:死后如何自动重新连接
【发布时间】:2014-04-21 07:45:38
【问题描述】:
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function () {
  ws.send(JSON.stringify({
      .... some message the I must send when I connect ....
  }));

};

ws.onmessage = function (e) {
  console.log('Got a message')
  console.log(e.data);
};

ws.onclose = function(e) {  
  console.log('socket closed try again'); 

}

ws.onerror = function(err) {
  console.error(err)
};

当我第一次连接到socket时,我必须先向服务器发送一条消息来验证自己并订阅频道。

我遇到的问题是,有时套接字服务器不可靠,这会触发 'ws' 对象的 onerroronclose 事件。

问题:有什么好的设计模式可以让我在套接字关闭或遇到错误时等待 10 秒,然后重新连接到套接字服务器(并将初始消息重新发送到服务器)

【问题讨论】:

标签: javascript websocket


【解决方案1】:

这就是我最终的结果。它适用于我的目的。

function connect() {
  var ws = new WebSocket('ws://localhost:8080');
  ws.onopen = function() {
    // subscribe to some channels
    ws.send(JSON.stringify({
        //.... some message the I must send when I connect ....
    }));
  };

  ws.onmessage = function(e) {
    console.log('Message:', e.data);
  };

  ws.onclose = function(e) {
    console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
    setTimeout(function() {
      connect();
    }, 1000);
  };

  ws.onerror = function(err) {
    console.error('Socket encountered error: ', err.message, 'Closing socket');
    ws.close();
  };
}

connect();

【讨论】:

  • 这是否会重新连接到它之前连接的同一个 websocket?因为我使用 websocket id 来发送消息,但是如果它有新的 websocket id 就很难将消息发送到特定系统。
  • @AlexanderDunaev,添加超时主要是为了避免在服务器不可用时过于激进的重新连接,即网络中断或本地调试服务器关闭。但总的来说,我认为立即重新连接,然后以指数级增长的重新连接等待时间比固定的 1 秒等待稍好一些。
  • 连接关闭时 websocket 实例会发生什么。是垃圾回收,还是浏览器堆积了一堆未使用的对象?
  • setTimeout(connect,1000) 是一种更简洁、更节省资源的延迟重新连接的方法。还可以考虑使用 setTimeout (connect ,Math.min(10000,timeout+=timeout)),在第一次连接之前和每次成功连接之后将超时重置为 250。这样,连接期间的错误情况会增加一个退避,但如果是一次性错误情况,则会快速重新连接 - 250,500,1000,2000,4000,8000,10000,10000 毫秒延迟不那么激进,但比 1000,1000 响应更快,1000 毫秒
  • 我在这段代码中看到的问题是,如果连接关闭,我们再次尝试打开连接,但失败了,那么我们将永远不会重试。
【解决方案2】:

这对我有用 setInterval,因为客户端连接可能会丢失。

ngOnInit(): void {
    if (window.location.protocol.includes('https')) {
        this.protocol = 'wss';
    }

    this.listenChanges();
}


listenChanges(): void {
    this.socket = new WebSocket(`${this.protocol}://${window.location.host}/v1.0/your/url`);

    this.socket.onmessage = (event): void => {
        // your subscription stuff
        this.store.dispatch(someAction);
    };

    this.socket.onerror = (): void => {
        this.socket.close();
    };


    this.socket.onopen = (): void => {
        clearInterval(this.timerId);

        this.socket.onclose = (): void => {
            this.timerId = setInterval(() => {
                this.listenChanges();
            }, 10000);
        };
    };
}

当套接字打开时不要忘记调用clearInterval

【讨论】:

    【解决方案3】:

    这不是一个明确的反应问题,但这是一个反应风格的答案:

    TLDR:您可以使用setInterval定期检查websocket连接状态,如果连接关闭则尝试重新连接。 https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState

    class TestComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {};
    
        this.connect = this.connect.bind(this);
      }
    
      componentDidMount() {
        this.interval = setInterval(this.connect, 1000);
      }
    
      componentWillUnmount() {
        if (this.ws) this.ws.close();
        if (this.interval) clearInterval(this.interval);
      }
    
      connect() {
        // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
        if (this.ws === undefined || (this.ws && this.ws.readyState === 3)) {
          this.ws = new WebSocket(`ws://localhost:8080`);
    
          this.ws.onmessage = (e) => {
            console.log(JSON.parse(e.data));
          };
        }
      }
    
      render() {
        return <div>Hey!</div>;
      }
    }
    

    【讨论】:

      【解决方案4】:

      原生 Websocket api 之上的一个非常有趣的包装器,可以很好地添加它

      https://github.com/joewalnes/reconnecting-websocket

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          我发现这个包https://github.com/pladaria/reconnecting-websocket可以解决Websocket连接的重连问题。它有一个可配置选项列表,其中之一是reconnectionDelayGrowFactor,它决定了重新连接延迟增长的速度。

          【讨论】:

            【解决方案7】:

            更新答案:

            最后,(如果您不使用 java)我发现您最好实现自己的“ping/pong”策略。 (如果你用的是java,请看一下ping/pong“动作类型”,我记不太清楚了……)

            1. 客户端每 5 秒向服务器发送一次“ping”。
            2. 服务器收到“ping”后,应向客户端回显“pong”。
            3. 如果在 5 秒内没有收到“pong”,客户端应该重新连接服务器。

            不要依赖任何第三方库。

            警告:请勿使用这些工具:(原因:它们不可靠且不稳定,并且工作方式非常有限。)

            1. 检查网络是否可用:https://github.com/hubspot/offline
            2. 重新连接:https://github.com/joewalnes/reconnecting-websocket

            【讨论】:

            • github 库github.com/joewalnes/reconnecting-websocket 实际上作为new WebSocket() 的一个简单连接的简单插件。我知道这个答案一般来说有点离题,但为了简单起见,在这里使用提到的 javascript 库确实有效。
            • 是的,你是对的!不要使用那 2 个 github 存储库。
            • 为什么我们不应该使用它们?第二个看起来很有用。
            • 你应该实施你的乒乓策略。不要相信打开/关闭事件。
            • 请注意,在我撰写本文时,ReconnectingWebSocket 不支持 'binaryType' 选项:它似乎有 50% 的时间退回到 'blob',并且缩小的 JS 不包含以下功能全部。所以我就自己动手了。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-11-27
            • 2021-01-20
            • 2022-08-05
            • 2019-08-05
            • 2010-11-08
            • 1970-01-01
            相关资源
            最近更新 更多