如何在关闭连接后重新连接WebSocket

61

我使用以下代码(例如)构建我的 WebSocket 连接:

var socket = new WebSocket("ws://94.12.176.177:8080");

我用这个来关闭连接:

socket.close();

但是我该如何重新建立连接?

我做了一些研究并尝试了几种方法。这个问题对我没有帮助:Socket.io断开连接后重新连接? 这是唯一一个接近我所寻找的答案。

我想这样做的原因是允许用户在网页上暂停发送数据,然后在一段时间后再次发送。如果没有重新连接,用户必须刷新页面才能重新发送。这可能会导致一些数据丢失。谢谢。


只需再创建一个新的WebSocket即可。重新连接不存在的原因是因为它可能就像创建一个新的一样。 - AHungerArtist
3
可能是*WebSocket中服务器重启时客户端如何重新连接的重复问题*的复制问题。 - Peter Mortensen
以下是可能的解决方案之一:https://github.com/gdi2290/angular-websocket/issues/100 - Tomasz Waszczyk
5个回答

94
当服务器关闭连接时,客户端不会尝试重新连接。用一些JS框架可能会这样做,但是问题被标记为纯Vanilla JS时,该答案是错误的。我有点沮丧,因为被接受并投票的答案明显是错误的,这让我在找到正确的解决方案时浪费了额外的时间。正确的解决方案在这里:WebSocket中服务器重启时客户端的重新连接。请注意,HTML标签已保留,不包括解释。

4
抱歉让您感到失望。原帖链接是一个关于“socket.io”的问题,那很可能是他所使用的框架。这个问题应该被标记为socket.io - Jivings
谢谢您提供的链接,它解决了我的问题。由于我正在使用没有框架的WebSocket,所以接受的答案并不合适。 - Chad
2
你指向的答案基本上与@Jivings建议的相同。除了这个没有提到socket.close实例方法。 - aegyed

35
我在这个页面上找到了一个很好的解决方案:https://sam-low.com/how-to-reopen-a-closed-websocket.html 一旦原始连接关闭,您需要创建一个新的WebSocket对象,并添加新的事件监听器。
function startWebsocket() {
  var ws = new WebSocket('ws://localhost:8080')

  ws.onmessage = function(e){
    console.log('websocket message event:', e)
  }

  ws.onclose = function(){
    // connection closed, discard old websocket and create a new one in 5s
    ws = null
    setTimeout(startWebsocket, 5000)
  }
}

startWebsocket();

请注意,如果重新连接时出现问题,新的WebSocket对象仍然会接收到另一个关闭事件,这意味着即使它从技术上来说从未打开过,onclose()也会被执行。这就是为什么延迟五秒是明智的 - 如果没有延迟,你可能会发现自己以可能会破坏某些东西的速度创建和销毁成千上万个websocket连接。

1
抱歉,这是优化的方式吗? - Ali Alizadeh

14

注意:该问题标记为socket.io,因此此答案仅针对socket.io
如许多人所指出的,此答案不适用于普通的网络套接字,它们不会在任何情况下尝试重新连接。

Websockets不会自动尝试重新连接。您需要重新创建套接字才能获得新连接。唯一的问题是您必须重新附加处理程序。

但是,实际上,Websockets旨在保持打开状态。

更好的方法是由服务器关闭连接。这样,WebSocket将触发onclose事件,但仍会继续尝试建立连接。当服务器再次监听时,连接将自动重新建立。


14
客户端套接字尝试重新建立连接的行为——我猜这是Socket.IO的事情?(不是基本的WebSockets的事情吧?) - UpTheCreek
4
@UpTheCreek,是的,我也这么认为。普通的WebSockets在调用 close() 后不会尝试重新连接。 - Jivings
我曾经使用过一个开源的纯AS3实现的WebSockets和TLS,但我决定浏览器的实现会更加更新,所以我创建了一个JS WebSocket管理器,我的AS3 WebSocket类调用它。该管理器构造具有唯一ID和回调的实例,将事件和套接字ID转发到Flash中的静态方法,然后在其中查找相应的AS3实例并在其上分派事件。这使我能够“重新连接();”,而无需重新附加事件处理程序,因为AS3 WebSocket只是在幕后请求新的JS WebSocket和ID。 - Triynko
13
当服务器关闭连接时,客户端并不会尝试重新连接。也许在一些JS框架中会这样做,但是该问题标记为原生的Vanilla JS。 - SzG
3
纯净的 JS 没有自动重新连接的好理由。谁愿意在 WebSocket 服务器宕机时让代理服务器受到打击呢?花些时间来实现适合你需求的重新连接策略吧。 - Daniel F
显示剩余4条评论

0

完美的实现:

var socket;

const socketMessageListener = (event) => {
  console.log(event.data);
};

const socketOpenListener = (event) => {
  console.log('Connected');
  socket.send('hello');
};

const socketCloseListener = (event) => {
  if (socket) {
    console.error('Disconnected.');
  }
  socket = new WebSocket('ws://localhost:8080');
  socket.addEventListener('open', socketOpenListener);
  socket.addEventListener('message', socketMessageListener);
  socket.addEventListener('close', socketCloseListener);
};

socketCloseListener();

测试一下:

setTimeout(()=>{
  socket.close();
},5000);

编辑:注意指数退避实现(在顶部评论的链接线程中:https://dev59.com/GG865IYBdhLWcg3whO3E#37038217),不在上面的代码中,但非常关键。

再次编辑:查看primusbackhttps://www.npmjs.com/package/back,这是一个灵活而性感的实现。


24
我不喜欢你把它说成“完美的执行”。完美是指什么?最好让别人通过投票来评判。你从关闭处理程序中创建套接字的方法很巧妙。也许这可以作为开头句子。 - akauppi
@Pol的答案更简洁、更清晰。 - jjxtra

-1

function wsConnection(url){
    var ws = new WebSocket(url);
    var s = (l)=>console.log(l);
 ws.onopen = m=>s(" CONNECTED")
    ws.onmessage = m=>s(" RECEIVED: "+JSON.parse(m.data))
    ws.onerror = e=>s(" ERROR")
    ws.onclose = e=>{
        s(" CONNECTION CLOSED");
        setTimeout((function() {
            var ws2 = new WebSocket(ws.url);
   ws2.onopen=ws.onopen;
            ws2.onmessage = ws.onmessage;
            ws2.onclose = ws.onclose;
            ws2.onerror = ws.onerror;
            ws = ws2
        }
        ).bind(this), 5000)
    }
    var f = m=>ws.send(JSON.stringify(m)) || "Sent: "+m;
    f.ping = ()=>ws.send(JSON.stringify("ping"));
    f.close = ()=>ws.close();
    return f
}

c=new wsConnection('wss://echo.websocket.org');
setTimeout(()=>c("Hello world...orld...orld..orld...d"),5000);
setTimeout(()=>c.close(),10000);
setTimeout(()=>c("I am still alive!"),20000);
<pre>
This code will create a websocket which will 
reconnect automatically after 5 seconds from disconnection.

An automatic disconnection is simulated after 10 seconds.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接