4

Does Nagle's Algorithm need to be disabled client side as well? If this is the case, I have not found a way to disable Nagle's algorithm through JavaScript alone.

I am trying to stream data across a websocket, from a PHP CLI server hosted on Raspbian OS (have also hosted on Windows 7 and Ubuntu with same results). This server has successfully created the socket and accepts multiple connections, and has set the TCP_NODELAY flag (verified with socket_get_option only).

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

On most platforms, regardless of this TCP_NODELAY flag being set, the data will stream without clumping. However, on Windows 7 Chrome and Firefox, the data arrives in chunks (with a telltale 0.2s delay). On Windows 8, Linux, iOS, and Windows 7's Internet Explorer 11: I don't see this problem at all.

http://www.13willows.com/hovelme/script/serverControl.php Here is the test website, click "Connect", then click "View Game" and you should see a Current Packet steadily incrementing from 1 to 20, every 50ms. However, on some clients, it jumps 4 at a time approx every 200ms.

Any ideas to get this to stop? Will using node.js / socket.io fix something like this and still allow me to run code from a user's browser?

TheWandererLee
  • 1,012
  • 5
  • 14

1 Answers1

2

At least Chrome seems to disable Nagle algorithm for all WebSocket sockets:

Worth noting that Chrome also disables the Nagle algorithm on all of its TCP sockets.

But it seems like NODELAY option should be enabled on both sides to guarantee low latency:

We already disable Nagle on all platforms, using just such a method, but that doesn't disable delaying ACKs (Or at least it doesn't on Windows, it's certainly possible it does elsewhere).

source

Chromium source code seems to proof this (but I'm not a Chromium developer, so I'm just guessing that the following code is called on all TCP sockets as one of commentators above said):

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
}

link to source line

See also this possible workaround idea - https://stackoverflow.com/a/13406438/3167374

shitpoet
  • 419
  • 5
  • 11