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


79
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)
};

当我第一次连接到套接字时,我必须先向服务器发送一条消息以对自己进行身份验证并订阅频道。

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

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


Answers:


143

这就是我最后得到的。它适用于我的目的。

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();

2
那会重新连接到以前连接过的同一websocket吗?因为我正在使用websocket id发送消息,但是如果它具有新的websocket id,将很难向特定系统发送消息。
Vishnu YS

17
@AlexanderDunaev,主要是通过添加超时来避免在服务器不可用(例如,网络断开或本地调试服务器关闭)时过于激进的重新连接。但总的来说,我认为立即重新连接,然后以指数方式增长的重新连接等待时间比固定的1秒等待时间更好。
user658991

13
关闭连接后,websocket实例会发生什么情况。它是垃圾收集,还是浏览器会堆积一堆未使用的对象?
旋钮

7
setTimeout(connect,1000)是一种更简洁,资源有效的延迟重新连接的方法。还可以考虑使用setTimeout(connect,Math.min(10000,timeout + = timeout)),在第一次连接之前和每次成功连接之后将超时重置为250。这样,连接期间的错误情况将增加退避,但如果是一次性错误情况,则会快速重新连接-250,500,1000,2000,4000,8000,10000,10000毫秒的延迟不那么激进,但响应速度比1000,1000快,1000毫秒
不同步,

3
我在这段代码中看到的问题是,如果连接已关闭,而我们尝试再次打开连接,但连接失败,那么我们将永远不会重试。
迈克尔·康纳

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插座打开后,别忘了打电话。



1

更新的答案:

最后,(如果您不使用Java),我发现您最好实施自己的“乒乓”策略。(如果您使用的是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

1
github库github.com/joewalnes/reconnecting-websocket实际上是new WebSocket()在简单连接中的简单插入。我知道这个答案总体上来说有点离题,但为简单起见,在这里使用提到的javascript库确实可行。
TechnicalChaos

是的,你是对的 !不要使用那两个github仓库。
沉思玮申思

2
为什么不使用它们?第二个看起来非常有用。
Shamoon

1
您应该实施乒乓球策略。不要相信打开/关闭事件。
沉思玮申思20'May

请注意,在撰写本文时,ReconnectingWebSocket不支持'binaryType'选项:它似乎有50%的时间回落到'blob',而且缩小的JS根本不包含该功能。所以我只是自己滚了。
离线
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.