socket.io 在 x 秒/第一次尝试获取响应失败后停止重新发出事件

Posted

技术标签:

【中文标题】socket.io 在 x 秒/第一次尝试获取响应失败后停止重新发出事件【英文标题】:socket.io stop re-emitting event after x seconds/first failed attempt to get a response 【发布时间】:2015-11-14 21:15:16 【问题描述】:

我注意到,每当我的服务器离线时,当我将其切换回在线时,它会收到大量套接字事件,这些事件在服务器关闭时被触发。 (现在已经过时的事件)。

有没有办法阻止 socket.io 在 x 秒内没有收到响应后重新发出事件?。

【问题讨论】:

您是否在几秒钟后将服务器切换回在线状态,然后收到服务器离线期间发生的所有事件?我很好奇您的服务器重启之间经过了多少时间。 服务器宕机多长时间似乎并不重要。我等了大约 10 分钟左右,当服务器重新联机时,套接字事件仍然进来。 (仅当用户浏览器/选项卡打开时才会发生这种情况)。服务器关闭的时间越长,它接收的事件就越多。 这是不寻常的行为。它应该只重试前 20 秒。你能发布一些你的客户端和服务器代码吗 这是 socket.disconnect 事件可以解决的问题吗? 【参考方案1】:

当开源库的所有其他方法都失败时,您可以研究代码,看看您能找出什么。在使用 socket.io 源代码做了一些时间之后......

问题的症结似乎是here in socket.emit() 中的这段代码:

  if (this.connected) 
    this.packet(packet);
   else 
    this.sendBuffer.push(packet);
  

如果套接字未连接,所有通过.emit() 发送的数据都缓存在sendBuffer 中。然后,当套接字再次连接时,我们会看到:

Socket.prototype.onconnect = function()
  this.connected = true;
  this.disconnected = false;
  this.emit('connect');
  this.emitBuffered();
;

Socket.prototype.emitBuffered = function()
  var i;
  for (i = 0; i < this.receiveBuffer.length; i++) 
    emit.apply(this, this.receiveBuffer[i]);
  
  this.receiveBuffer = [];

  for (i = 0; i < this.sendBuffer.length; i++) 
    this.packet(this.sendBuffer[i]);
  
  this.sendBuffer = [];
;

因此,这完全解释了为什么它会在连接断开时缓冲所有发送的数据,然后在重新连接时将其全部发送。

现在,关于如何阻止它发送这个缓冲的数据,这里有一个理论,我将在今晚晚些时候有更多时间时尝试测试。

有两件事看起来像是一个机会。套接字在发送缓冲数据之前通知connect 事件,sendBuffer 是套接字的公共属性。因此,看起来您可以在客户端代码中执行此操作(在连接时清除缓冲区):

// clear previously buffered data when reconnecting
socket.on('connect', function() 
    socket.sendBuffer = [];
);

我刚刚测试了它,它工作得很好。我有一个客户端套接字,它每秒向服务器发送越来越多的计数器消息。我将服务器关闭 5 秒钟,然后当我在添加此代码之前恢复服务器时,所有排队的消息都会到达服务器。没有错过任何计数。

然后,我添加上面的三行代码,在服务器关闭时发送的任何消息都不会发送到服务器(从技术上讲,它们在发送之前从发送缓冲区中清除)。它有效。


仅供参考,另一种可能性是在套接字未连接时不调用.emit()。因此,您可以创建自己的函数或方法,仅在套接字实际连接时尝试.emit(),因此不会有任何东西进入sendBuffer

Socket.prototype.emitWhenConnected = function(msg, data) 
    if (this.connected) 
        return this.emit(msg, data);
     else 
        // do nothing?
        return this;
    

或者,更危险的是,您可以覆盖 .emit() 使其以这种方式工作(不是我的建议)。

【讨论】:

感谢两位的提问和回答。节省了很多时间自己调查。我可以使用“on connect, clear sendBuffer”方法来确认成功。就我而言,我做了“sio.on('connect', function(data) sio.sendBuffer.length = 0; ...” 并且使用 socketio 2.1.2 效果很好,没有明显的不良副作用. @jfriend00 非常好的答案,但 socket.sendBuffer 似乎不适用于 npm socket.io v2.3.0。我有一条路线,我向用户发出一些代码,当出现问题时,用户被重定向到起始页面,他需要再次填写输入字段(希望这次使用正确的数据,这样他就不会再次被重定向)。我的问题是,当他使用相同的路由时,所有套接字都会发出两次 - 即使使用 socket.sendBuffer = [];对此有什么想法吗?谢谢! @b4rtekb - 我们必须查看您的实际代码才能知道建议的内容。请编写您自己的问题,其中包含您的特定代码。通常双重发射是因为你不小心在某个地方有双重事件处理程序。 太棒了!这是问题 - ***.com/questions/62679013/… 我随时可以通过 bartekb@gmail.com 联系,谢谢。 @jfriend00 我有一个关于重新发送的类似问题,但它是针对服务器端的。你能看一下,也许能解释一下吗?谢谢! ***.com/questions/62992888/…

以上是关于socket.io 在 x 秒/第一次尝试获取响应失败后停止重新发出事件的主要内容,如果未能解决你的问题,请参考以下文章

Socket io 延迟一个事件

当我打开新窗口时,socket.io 得到不好的响应

socket.io 和 node.js 400 错误请求

如何使用套接字(socket.io)在 NodeJS 中找到客户端的响应时间(延迟)?

集成测试 node.js socket.io 服务器

Socket.io 1.x:只使用 WebSockets?