简体   繁体   English

Chrome 中的 WebSockets 和 Firefox 在闲置一分钟后断开连接

[英]WebSockets in Chrome and Firefox Disconnecting After One Minute of Inactivity

I have found that WebSockets in Chrome and Firefox disconnect after exactly one minute of inactivity.我发现 Chrome 中的 WebSockets 和 Firefox 在闲置一分钟后断开连接。 Based on stuff I've seen online, I was all set to blame proxies or some server settings or something, but this does not happen in IE or Edge.根据我在网上看到的东西,我都将责任归咎于代理或某些服务器设置或其他东西,但这不会发生在 IE 或 Edge 中。 It seems like if sockets are disconnected by the server after one minute of inactivity that would apply to IE and Edge just as much as Chrome and Firefox.似乎如果 sockets 在一分钟不活动后被服务器断开连接,这将适用于 IE 和 Edge,就像 Chrome 和 Firefox 一样。

Does anyone know why this is?有人知道为什么吗? Is it documented anywhere?它记录在任何地方吗? I know a possible way to stop it by pinging, but I'm more interested in why it's happening.我知道一种通过 ping 来阻止它的可能方法,但我对它发生的原因更感兴趣。 The reason code given on disconnect is 1006, indicating that the browser closed the connection. disconnect给出的原因码是1006,表示浏览器关闭了连接。 No errors are thrown and the onerror event for the socket is not triggered.不会抛出任何错误,也不会触发套接字的 onerror 事件。

This project was built at https://glitch.com/edit/#!/noiseless-helmet where you can see and run everything.该项目构建于https://glitch.com/edit/#!/noiseless-helmet ,您可以在其中查看和运行所有内容。 The client page is served here: https://noiseless-helmet.glitch.me/客户端页面在此处提供: https://noiseless-helmet.glitch.me/

Here is my client page:这是我的客户页面:

<div id="div">
</div>
<script>
  let socket = new WebSocket("wss://noiseless-helmet.glitch.me/");
  socket.onmessage = function(event) {
    div.innerHTML += "<br>message " + new Date().toLocaleString() + " " + event.data;
  };
  socket.onopen = function (event) {
    div.innerHTML += "<br>opened " + new Date().toLocaleString();
    socket.send("Hey socket! " + new Date().toLocaleString());
  };
  socket.onclose = function(event) {
    div.innerHTML += "<br>socket closed " + new Date().toLocaleString();
    div.innerHTML += "<br>code: " + event.code;
    div.innerHTML += "<br>reason: " + event.reason;
    div.innerHTML += "<br>clean: " + event.wasClean;
  };
  socket.onerror = function(event) {
    div.innerHTML += "<br>error: " + event.error;
  };
</script>

And here is my Node.js server code:这是我的 Node.js 服务器代码:

var express = require('express');
var app = express();
app.use(express.static('public'));

let server = require('http').createServer(),
  WebSocketServer = require('ws').Server,
  wss = new WebSocketServer({ server: server });

app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

let webSockets = [];
wss.on('connection', function connection(socket) {
  webSockets.push(socket);
  webSockets.forEach((w) => { w.send("A new socket connected"); });
  socket.on('close', (code, reason) => {
    console.log('closing socket');
    console.log(code);
    console.log(reason);
    let i = webSockets.indexOf(socket);
    webSockets.splice(i, 1);
  });
});

server.on('request', app);
server.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + server.address().port);
});

As much as i understood from researching this, this is caused by websocket timing out over a period of time when no data is sent. 正如我从研究中所理解的那样,这是由于在没有数据发送的一段时间内websocket超时引起的。 This is probably per browser. 这可能是每个浏览器。

You could use pings to resolve this or just reconnect when you need to use the socket again. 您可以使用ping来解决此问题,或者只在需要再次使用套接字时重新连接。

It makes sense to not keep sockets open when they are not used from server side as from browser side. 当从服务器端而不是从浏览器端使用套接字时,不保持套接字打开是有意义的。 For example, Chrome has a limit how many connections can be open, if the limit would be 64 connections and you have open 64 tabs (which is very likely for me as i always have loads of tabs open) and each tab is connected to a server, no more connections could be done (Actually similar thing happened to me once, when i ran out of available sockets in Chrome, funny). 例如,Chrome有一个限制可以打开多少个连接,如果限制为64个连接并且您打开了64个标签(这对我很有可能,因为我总是打开大量标签)并且每个标签都连接到服务器,没有更多的连接可以做(实际上类似的事情发生在我身上,当我用完Chrome中的可用套接字时,很有趣)。

There is proxy_read_timeout ( http://nginx.org/r/proxy_read_timeout ) which as well applies to WebSocket connections. 有proxy_read_timeout( http://nginx.org/r/proxy_read_timeout ),它也适用于WebSocket连接。 You have to bump it if your backend do not send anything for a long time. 如果你的后端长时间不发送任何东西,你必须碰撞它。 Alternatively, you may configure your backend to send websocket ping frames periodically to reset the timeout (and check if the connection is still alive). 或者,您可以将后端配置为定期发送websocket ping帧以重置超时(并检查连接是否仍处于活动状态)。

https://forum.nginx.org/read.php?2,236382,236383#msg-236383 https://forum.nginx.org/read.php?2,236382,236383#msg-236383

Web Sockets have an idle timeout of 60 seconds : if you do not use a heartbeat or similar via ping and pong frames then the socket assumes that the user has closed the page and closes the socket to save resources. Web套接字的空闲超时为60秒 :如果您不使用心跳或类似的ping和pong帧,则套接字假定用户已关闭页面并关闭套接字以节省资源。

https://www.codeproject.com/Questions/1205863/Websocket-is-closed-after-min https://www.codeproject.com/Questions/1205863/Websocket-is-closed-after-min

https://github.com/tornadoweb/tornado/issues/1070 https://github.com/tornadoweb/tornado/issues/1070

It seems like if sockets are disconnected by the server after one minute of inactivity that would apply to IE and Edge just as much as Chrome and Firefox. 看起来,如果服务器在一分钟不活动后断开连接,这将适用于IE和Edge,就像Chrome和Firefox一样。

Hmmm, no, it doesn't. 嗯,不,它没有。 IE and Edge might be implementing a ping packet as part of the WebSocket protocol. IE和Edge 可能正在实施ping数据包作为WebSocket协议的一部分。

The WebSocket protocol includes support for a protocol level ping that the JavaScript API doesn't expose. WebSocket协议包括对JavaScript API不公开的协议级别ping支持 It's a bit lower-level than the user level pinging that is often implemented. 它比通常实现的用户级别ping更低级别。

This ping - pong traffic resets the timers in any network intermediaries (proxies, load balancers, etc') - and they all time connections to mark stale connections for closure (for example, the Heroku setup times connections at 55 seconds ). 这个ping - pong流量重置计时器中的任何网络媒介(代理,负载平衡器等') -和它们所有的时间连接到标记为陈旧关闭连接(例如, 以55秒的Heroku设置时间的连接 )。

Most browsers trust the server to implement the ping , which is polite (since servers need to manage their load and their timeout for pinging... 大多数浏览器都信任服务器实现ping ,这是礼貌的(因为服务器需要管理他们的负载和他们的ping超时...

...however it's also slightly frustrating, since browsers have no idea if a connection was abnormally lost. ...但是它也有点令人沮丧,因为浏览器不知道连接是否异常丢失。 This is why many JavaScript clients implement a user level ping (ie, a JSON {event: "ping", data: {...}} or another "empty" event message). 这就是许多JavaScript客户端实现用户级ping的原因(即JSON {event: "ping", data: {...}}或另一个“空”事件消息)。

Anyway, I just wanted to point out that your assumption was incorrect, this is still a timeout occurring and the difference in browser behavior is probably related to the browsers themselves. 无论如何,我只是想指出你的假设不正确,这仍然是超时发生,浏览器行为的差异可能与浏览器本身有关。

For a few specifics regarding nginx default timeouts (when proxying WebSocket connections) you can read @Hendry's answer. 有关nginx默认超时的一些细节(当代理WebSocket连接时),您可以阅读@Hendry的答案。

The WebSocket protocol specification defines Ping and Pong frames that can be used for keep-alive, heart-beats, network status probing. WebSocket协议规范定义了Ping和Pong帧,可用于保持活动,心跳,网络状态探测。 Ping means client/server is sending an iq to tell the other side server/client that to keep the connection alive and also the other side will send an acknowledgement with pong having same payload data. Ping意味着客户端/服务器正在发送iq以告知对方服务器/客户端保持连接活动,并且另一方将发送具有相同有效载荷数据的pong的确认。

You can also define a timeout when the browser stops respond or be considered dead. 您还可以在浏览器停止响应或被视为已死时定义超时。

read more: http://vunse.blogspot.in/2014/04/websocket-ping-pong.html 阅读更多: http//vunse.blogspot.in/2014/04/websocket-ping-pong.html

Maybe not a clean solution but this is how I implemented websocket in JS to automatically reconnect when disconnected也许不是一个干净的解决方案,但这就是我在 JS 中实现 websocket 以在断开连接时自动重新连接的方式

var socket_main
const mainSocketMessageListener = (event) => {
  //retreive the data here
  console.log(event.data)
}

const mainSocketOpenListener = (event) => {
  console.log("Websocket opened")
  //Example of sending message to websocket here
  socket_main.send(JSON.stringify({
    event: "subscribe",
    data: ["all"]
  }))
}

const mainSocketCloseListener = (event) => {
  if (socket_main) {
    console.error('Websocket disconnected.')
  }
  socket_main = new WebSocket('wss://ws.example.com')
  socket_main.addEventListener('open', mainSocketOpenListener)
  socket_main.addEventListener('message', mainSocketMessageListener)
  socket_main.addEventListener('close', mainSocketCloseListener)
}

//connect the first time
mainSocketCloseListener()

I think the issue is related to policy changes on chrome and other browsers.我认为这个问题与 chrome 和其他浏览器的政策变化有关。

Please see discussions at请参阅讨论

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM