Node.js Socket.io 页面刷新多个连接

Posted

技术标签:

【中文标题】Node.js Socket.io 页面刷新多个连接【英文标题】:Node.js Socket.io page refresh multiple connections 【发布时间】:2017-06-14 22:47:24 【问题描述】:

我有这个使用 socket.io (1.5) 的简单 node.js 服务器代码:

var io = require('socket.io').listen(8080);

io.on('connection', function(socket) 

    console.log(' %s sockets connected', io.engine.clientsCount);

    socket.on('disconnect', function() 
        console.log("disconnect: ", socket.id);
    );
);

如果我运行此代码并按 F5 几次,在某些情况下,会在旧连接断开之前创建新连接。一段时间后,我认为是心跳超时,所有连接都将关闭。查看结果:

 2 sockets connected
 3 sockets connected
 4 sockets connected
 5 sockets connected
 6 sockets connected
 7 sockets connected
 8 sockets connected
 9 sockets connected
 10 sockets connected
 11 sockets connected
disconnect:  0h_9pkbAaE3ftKT9AAAL
 11 sockets connected
 12 sockets connected
 13 sockets connected
 14 sockets connected
disconnect:  oB4HQRCOY1UIvvZkAAAP
 14 sockets connected
 15 sockets connected
disconnect:  LiIN0oDVoqbePgxFAAAR
 15 sockets connected
 16 sockets connected
 17 sockets connected
 18 sockets connected
disconnect:  zxvk-uhWABHzmu1uAAAV
 18 sockets connected
 19 sockets connected
 20 sockets connected
disconnect:  FlboxgTzcjf6ScffAAAY
 20 sockets connected
 21 sockets connected
disconnect:  9UGXbnzukfGX_UtWAAAa
 21 sockets connected
disconnect:  pAfXOEz6RocKZdoZAAAb
 21 sockets connected
disconnect:  DIhTyVgG2LYBawaiAAAc
 21 sockets connected
disconnect:  W4XOc1iRymfTE2U0AAAd
 21 sockets connected
disconnect:  WZzegGPcoGDNLRTGAAAe
 21 sockets connected
 22 sockets connected
disconnect:  KVR3-fYH0cz77BmgAAAC
disconnect:  ANQknhnxr4l-OAuIAAAD
disconnect:  KZE5orNx6u9MbOArAAAE
disconnect:  TS6LL3asXrcznfcPAAAF
disconnect:  SVNxS3I7KqecdqKhAAAG
disconnect:  IE2WE5Y0PJzvxgBfAAAH
disconnect:  v69bdJav9PjpThBGAAAI
disconnect:  mJKT1ggfOOTshZKgAAAJ
disconnect:  YlycVjdcWe0emCAcAAAK
disconnect:  MoIDJSzP_L-1RUwuAAAM
disconnect:  wAl0x5qwCkrnDDYQAAAN
disconnect:  eiTlPEk2Hx_X-L-fAAAO
disconnect:  KgkrXxzG_EpXOsPTAAAQ
disconnect:  Lvf3kK-6XXEbu3NWAAAS
disconnect:  -hOoGdYOIvVK04K_AAAT
disconnect:  3EUmaAYpK-U3Ss9tAAAU
disconnect:  HQ6M98FebtKlU3OfAAAW
disconnect:  OwgrbRBYbS4j84nmAAAX
disconnect:  yN8FZAP4RjUNl2MeAAAZ
disconnect:  K9IFTjlgAWzdNfpUAAAf

我的问题是: 这是 Bug 还是 socket.io 的正常行为?如何防止连接泛滥,只需按 F5?

最好的问候 马克

【问题讨论】:

刷新浏览器时浏览器应该关闭打开的 webSockets,然后你应该断开连接。如果不是,那将是一个浏览器错误。如果浏览器没有立即关闭 webSocket,socket.io 将看到套接字不再处于活动状态(因为心跳)并且套接字最终会被清理。 所有实际浏览器都会发生这种情况。 从您按 F5 到服务器最终断开连接之间的时间量是多少?您的计数似乎也有问题,因为您在断开连接时没有显示计数减少。 如果您只按 F5 一次,立即断开连接。但是,如果你按 F5 足够快,一些 disennects 就会“丢失”。我不认为计数器有错,因为示例服务器仅在新连接打开时才计数 我对计数器的评论是您收到了断开连接的消息,但计数并没有下降。这在您的日志记录中似乎很明显。如果只是快速刷新导致问题,我不知道你为什么担心这个问题。他们会在短时间内自行清理,因此不会意外长期积累任何东西。这会引起任何实际问题吗?您可以缩短 socket.io 不活动超时,以便它们更快地清理自己,但这可能会造成其他妥协,所以如果它实际上没有引起真正的问题,我不会改变。 【参考方案1】:

我制作了自己的测试应用,并且能够弄清楚发生了什么。

如果你多次快速按F5,它确实会在Chrome中暂时积累一些额外的socket.io连接,但在相对较短的时间内(可能几分钟),它会恢复并且连接的套接字总数恢复到1.

经过进一步测试,我发现这不是浏览器问题。这是 socket.io 如何启动 socket.io 连接的问题。如果您在客户端中替换它:

var socket = io();

用这个:

var socket = io(transports: ['websocket'], upgrade: false);

这迫使 socket.io 只使用 webSocket 而从不使用 HTTP 轮询,然后问题就消失了。

所以,问题是因为 socket.io 的默认行为是从 socket.io 连接的 http 轮询版本开始。在交换了一些数据后,socket.io 将尝试切换到真正的 webSocket。如果那个真正的 webSocket 有效,那么它将停止使用 http 轮询连接。

但是,如果你在轮询和真正的 webSocket 之间的转换过程中按下 F5,那么 socket.io 还没有持久连接,它知道它刚刚与之通信的网页现在已经消失了。因此,它所能做的就是在一段时间后弄清楚该网页不再有任何传入通信,因此它应该清除它的 socket.io 连接(当你按下 F5 时它处于轮询模式)。

但是,如果您使用上面的客户端代码关闭初始轮询模式,那么它只会使用真正的 webSocket(从不使用模拟轮询模式),并且当您按下 F5 时浏览器非常擅长清理 webSocket所以服务器要么没有完成建立它的 socket.io 连接(在这种情况下,还没有连接暂时被孤立),要么它已经转换为 webSocket(浏览器将在 F5 上干净地关闭它)。

因此,这是 socket.io 启动的 http 轮询模式的设计限制。由于在该模式下没有持续连接,因此当该页面被替换为 F5 时浏览器不会立即通知,因此服务器无法知道客户端刚刚消失。但是,如果您跳过 http 轮询模式并从真正的 webSocket 开始,那么就不存在有 socket.io 连接但没有真正的 webSocket 的时间窗口,因此浏览器总是会立即通知服务器关闭 webSocket当页面消失时连接。

【讨论】:

啊,好吧,这是有道理的。在客户端和服务器上编辑套接字连接后,问题不再发生。谢谢你的解释! @jfriend00 - 这对处理页面刷新非常有帮助。我使用flask-socket-io 作为后端,但这种技术应该始终在客户端socket-io 中工作。【参考方案2】:

解决方案:前后更新你的 socket.io 包的版本

示例:返回:socket.io 3.0.3

示例:前面:socket-io-client 3.0.3

现在是兼容的,传输套接字是 websocket 而不是轮询!

从 .... 导入 io。

const socket = io('http//localhost:3000') -> 服务器节点

【讨论】:

这完全解决了我的问题,前端和后端有不同的版本【参考方案3】:

我遇到了同样的错误,我与同一个用户建立了多个连接,错误是我在后端使用了不同的版本,我在前端添加了这段代码:

socket.on("connect_error", (err) => 控制台.log(connect_error due to $err.message); );

这样,我可以知道错误,我希望这可以帮助某人

【讨论】:

此答案与问题无关

以上是关于Node.js Socket.io 页面刷新多个连接的主要内容,如果未能解决你的问题,请参考以下文章

Node.js Socket.io 设置多个连接

Node.js + Socket.io 内存泄漏和最大监听器

使用 Socket.io 将客户端连接到服务器

使用 Socket.IO 将 Node.JS 服务器连接到另一个 Node.JS 服务器?

将 Socket.io 浏览器客户端连接到本地 Node.js 网络服务器

无法从Win Forms C#app连接到远程Node.js Socket.IO服务器