WebSocket:死后如何自动重新连接

Posted

技术标签:

【中文标题】WebSocket:死后如何自动重新连接【英文标题】:WebSocket: How to automatically reconnect after it dies 【发布时间】:2014-03-16 01:04:44 【问题描述】:
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 秒,然后重新连接到套接字服务器(并将初始消息重新发送到服务器)

【问题讨论】:

Reconnection of Client when server reboots in 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】:

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

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

更新答案:

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

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

不要依赖任何第三方库。

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

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

【讨论】:

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

如果需要,您可以使用small library - ReconnectingWebSocket

在您的脚本标签中添加 reconnecting-websocket.js

它是 API 兼容的,所以当你有:

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

您可以替换为:

var ws = new ReconnectingWebSocket('ws://....');

【讨论】:

以上是关于WebSocket:死后如何自动重新连接的主要内容,如果未能解决你的问题,请参考以下文章

WebSocket 实战

tomcat 7.0支持的最大活动websocket连接数是多少

C#winform程序卡死后 自动关闭后重启 怎么做

socket 用disconnect 断开,再重新连接怎么搞

WebSocket简介

websocket._exceptions.WebSocketProxyException:通过代理连接失败状态:503