【问题标题】:websocket client intermittently fails to transmit when making rapid calls to socket.send()快速调用 socket.send() 时,websocket 客户端间歇性地无法传输
【发布时间】:2014-03-29 17:14:12
【问题描述】:

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

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

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

【问题讨论】:

  • “服务器不是问题” - 你怎么知道的?可能是您正在使用删除消息的模块,对吗? “我正在尝试嗅探 TCP 流量......” - 你看过 chrome 中的网络选项卡吗?如果单击 websocket 连接,您可以看到浏览器认为已发送/接收的帧。知道消息是否显示在那里会很有用。你有连接到套接字的onerror 处理程序吗?
  • - 服务器使用 node.js 中的“net”模块实现。调试代码告诉我数据何时到达服务器。我在客户端有一个 onerror 处理程序,它不会触发。我可以在 chrome.network 中看到框架,但它们并没有告诉我太多信息。如何查看浏览器认为它发送的数据?
  • 我不确定服务器是否有问题。但是我不明白时间问题如何可能是服务器故障。因此,我试图查看 tcp 流量,希望了解浏览器是否真的在传输数据。
  • 哦,您使用的是原始net。为什么不呢,例如 ws 模块?
  • 我在框架选项卡中看到类似 dev-trello-attachments.s3.amazonaws.com/… 的内容 - 绿色是客户端发送的框架,白色是服务器发送的。

标签: javascript node.js tcp websocket


【解决方案1】:

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

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

这将导致同一个 IP 数据包中有多个 WebSocket (WS) 帧。一个表现良好的 WS 服务器只会读入 TCP 帧,只要 WS 帧的标头表明有数据。理解 Nagle 算法的行为良好的 WS 服务器然后将检查另一个 WS 帧以进行解码。

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 2015-09-06
      • 1970-01-01
      相关资源
      最近更新 更多