在快速调用socket.send()时,websocket客户端间歇性地无法传输

时间:2014-02-26 17:27:23

标签: javascript node.js tcp websocket

我有一个websocket服务器和客户端。我能够建立连接并在两个方向上传输消息(数据)。但是,当在Web浏览器中运行的客户端快速调用socket.send()时,服务器不会收到某些消息。如果我减慢客户端对socket.send()的调用,则服务器会收到所有消息。为什么调用socket.send()的时间与间歇性丢弃消息有关?

  • 在Win7,Android和iO上运行Chrome,FireFox和Safari时会出现这种情况。因此,我不认为这是一个浏览器错误。
  • 服务器是nodejs,但这不相关,因为服务器不是问题。
  • 通过快速调用,我的意思是调用是在requireAnimationFrame()控制的循环中进行的。
  • 消息中的数据量很小,每个大约40个字节。有< 10条消息,即连续调用socket.send()。因此,我不知道如何溢出TCP缓冲区。但也许?
  • websocket处于'arraybuffer'模式。
  • socket.bufferedAmount === 0每次发送之前和之后,无论客户端是否删除了该消息。
  • 套接字在丢弃消息后继续向两个方向发送消息。例如,客户端将对socket.send()进行10次调用,服务器将看到除3和7之外的所有消息,而客户端将看到服务器发送的所有消息。
  • 我已经在调用socket.send()之前验证了数据的完整性。客户端代码调用var tmpArrayBuffer = new ArrayBuffer(n)在每次调用socket.send(tmpArrayBuffer)之前创建一个新的缓冲区。因此,我认为我的客户端代码不会覆盖自己的缓冲区。
  • 从来没有一个错误信息的案例。消息要么完好无损,要么根本不到达。大多数邮件都会到达。
  • 我的老C程序员认为这是一个过度编写缓冲区的情况。但是我没有看到javascript中的可能性,并且鉴于socket.send()应该是我对数据负责的最终结果。
  • 我试图使用MS Message Analyzer嗅探客户端和服务器之间的TCP流量。然而,这是一个挑战,因为带有websocket密钥的浏览器XOR意味着我必须手动解密每条消息。慢而且没有乐趣。任何人都有更好的主意吗?
  • 我的代码是一个较大的项目的一部分,该项目太大而且错综复杂,无法发布。我正在研究一个小测试存根,它可能有助于调试问题。如果/当我让它工作时,我会发布存根。在任何情况下,当对socket.send()的调用及时间隔时,较大的项目“工作”,因此我不认为这是项目中其他地方的代码的问题。
  • 我认为这是我对如何使用websockets和/或TCP的理解问题。
  • 另一个线程建议使用反病毒软件(stackoverflow问题21191620)。我试过禁用我的防病毒软件。没有效果。此外,Android手机和iTouch上的问题完全相同,后者没有运行防病毒软件。

这是多年来我第一次无法通过stackoverflow等网站在网上进行研究来解决问题。我用Google搜索了这个问题,直到我的手指麻木。因此,我最终在这里创建了一个帐户并发布了一个问题请帮忙!

2 个答案:

答案 0 :(得分:2)

问题出在服务器上,而不是客户端。 Node.js在单个回调中传递多个消息。我的代码假设每ws消息回调一次。在消息以高速传递之前,这不是问题。修改服务器代码以解析各个消息后,问题就会消失。快乐的日子!

答案 1 :(得分:0)

具体原因是Nagle's Algorithm(维基百科链接)。

具体来说,如果在很短的时间内发送了几条消息,TCP可能会将一些消息组合到同一个TCP帧中。

这将导致同一IP数据包中的多个WebSocket(WS)帧。一个表现良好的WS服务器只会读入TCP帧,只要WS帧的头部表示有数据即可。理解Nagle算法的表现良好的WS服务器将检查另一个要解码的WS帧。

我在开发基于PHP的WS服务器时遇到的一个问题是,一旦服务器读取到第一条消息的末尾,如果有剩余数据,网络堆栈会在我发出大声抱怨的时候尝试检查新数据包。

表现不佳的WS服务器可能会读取WS框架表示数据结束的位置,并且要么在第一个消息的数据中包含第二个消息的WS帧,要么以奇怪和不寻常的方式失败。

如果您绝对必须进行实时通信,则TCP_NODELAY标志可用。然而,为了大多数人的网络,通常认为让Nagle的算法排队和合并消息是很好的方式。

这通常只是服务器方面的问题,因为绝大多数WS客户端都是Web浏览器,它们已经知道Nagle的算法。