socket.io |由于频率和音量而丢失消息

socket.io | losing messages due to frequency and volume

我有大约 5700 条消息(每条消息都是一个 100x100 图像作为 Base64 字符串),我在 for 循环中从服务器发送到客户端,非常快:

[a pretty big array].forEach((imgAsBase64) => {
  io.emit('newImgFromServer', imgAsBase64)
})

客户端总共只收到了1700到3000个,我才收到:

disconnected due to =  transport error
socket connected

一旦套接字重新连接(并且 for 循环尚未结束),循环内的新消息就会恢复,但我已经永远丢失了以前的消息。

如何确保客户端每次都能收到所有消息?

这个问题是“饿死事件循环”的一个有趣的例子。如果您在一段时间内处于紧密的 for 循环中并且循环中没有 await,那么您不要让事件循环在 [=10] 期间处理任何其他事件=] 循环。如果在此期间需要处理某些事件才能正常工作,就会出现问题。请继续阅读以了解如何将其应用于此案例。

客户端和服务器都需要一些偶尔的周期来处理 socket.io 协议中的内务处理 ping 和 pong。如果你在一个不间断的 for 循环中从一端向另一端发送消息,你可能会失去处理这些内务处理消息的能力,它会认为它已经超时(在它应该接收到内务处理消息时没有收到有这通常是连接丢失或失效的标志)。实际上,内务处理消息位于事件循环中等待处理,但如果您从不给事件循环处理它们的机会,for 循环中的一些其他代码 运行ning 会认为他们从未到达。

因此,您必须确保为两端提供足够的临时周期来处理这些内务处理消息。这样做的典型方法是确保您没有消防水龙头消息。发送 N 条消息,然后暂停一小段时间(事件循环有足够的时间来处理任何传入的网络事件)。然后再发N个,暂停等...

此外,您可以通过将多个 Base64 字符串组合成一条消息来使整个过程更加高效。您可以将它们放入一个包含 100 个的数组中,然后发送这个包含 100 个的数组并重复,直到它们全部发送完。然后,显然将客户端更改为期望一组 Base64 字符串而不是单个字符串。这显然会导致发送的消息少得多(效率更高),但您仍然需要时不时地暂停一下,让服务器在事件循环中处理事情。

暂停前究竟要发送多少条消息可以通过反复试验来计算,但是如果您将 100 张图像放入一条消息中并发送其中 10 条较大的消息(发送 1,000 张图像)然后暂停即使只是 50 毫秒,这应该足以让事件循环为来自 socket.io 的任何入站确认消息提供服务以避免超时。使用 setTimeout() 的任何类型的暂停都会使 setTimeout() 排在事件循环中等待的大多数其他消息之后,因此即使使用 setTimeout() 的短暂暂停也往往会实现让事件循环处理等待 运行.

的事情

如果端到端时间非常重要,您可以尝试一次发送更多消息 and/or 更改暂停时间,但您不想以接近于超时的地方(你想要一些安全系数)。