3

Nagle 算法是否也需要禁用客户端?如果是这种情况,我还没有找到单独通过 JavaScript 禁用 Nagle 算法的方法。

我正在尝试从托管在 Raspbian OS 上的 PHP CLI 服务器(也托管在 Windows 7 和 Ubuntu 上,结果相同)通过 websocket 流式传输数据。此服务器已成功创建套接字并接受多个连接,并已设置 TCP_NODELAY 标志(仅使用 socket_get_option 验证)。

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
socket_set_option($sock, SOL_SOCKET, TCP_NODELAY, 1);

在大多数平台上,无论是否设置了这个 TCP_NODELAY 标志,数据都会流式传输而不会聚集。但是,在Windows 7 Chrome 和 Firefox 上,数据以块的形式到达(有 0.2 秒的延迟)。在Windows 8、Linux、iOS 和 Windows 7 的 Internet Explorer 11 上:我根本看不到这个问题

http://www.13willows.com/hovelme/script/serverControl.php 这里是测试网站,点击“连接”,然后点击“查看游戏”,你应该会看到一个 Current Packet 从 1 到 20,每 50 毫秒稳步递增. 但是,在某些客户端上,它大约每 200 毫秒一次跳跃 4 次。

有什么想法可以阻止这种情况吗?使用 node.js / socket.io 会修复这样的问题,并且仍然允许我从用户的浏览器运行代码吗?

4

1 回答 1

0

至少 Chrome 似乎禁用了所有 WebSocket 套接字的 Nagle 算法:

值得注意的是,Chrome 还在其所有 TCP 套接字上禁用了 Nagle 算法。

但似乎应该在两侧启用 NODELAY 选项以保证低延迟:

我们已经在所有平台上禁用了 Nagle,只使用了这种方法,但这并没有禁用延迟 ACK(或者至少它不会在 Windows 上,它肯定有可能在其他地方这样做)。

资源

Chromium 源代码似乎证明了这一点(但我不是 Chromium 开发人员,所以我只是猜测在所有 TCP 套接字上调用以下代码,正如上面的评论员之一所说):

void TCPSocketPosix::SetDefaultOptionsForClient() {
  DCHECK(socket_);

  // This mirrors the behaviour on Windows. See the comment in
  // tcp_socket_win.cc after searching for "NODELAY".
  // If SetTCPNoDelay fails, we don't care.
  SetTCPNoDelay(socket_->socket_fd(), true);

  // TCP keep alive wakes up the radio, which is expensive on mobile. Do not
  // enable it there. It's useful to prevent TCP middleboxes from timing out
  // connection mappings. Packets for timed out connection mappings at
  // middleboxes will either lead to:
  // a) Middleboxes sending TCP RSTs. It's up to higher layers to check for this
  // and retry. The HTTP network transaction code does this.
  // b) Middleboxes just drop the unrecognized TCP packet. This leads to the TCP
  // stack retransmitting packets per TCP stack retransmission timeouts, which
  // are very high (on the order of seconds). Given the number of
  // retransmissions required before killing the connection, this can lead to
  // tens of seconds or even minutes of delay, depending on OS.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  const int kTCPKeepAliveSeconds = 45;

  SetTCPKeepAlive(socket_->socket_fd(), true, kTCPKeepAliveSeconds);
#endif
}

链接到源代码行

另请参阅这个可能的解决方法 - https://stackoverflow.com/a/13406438/3167374

于 2022-02-05T22:10:27.887 回答