使用tcp_nodelay发送大消息时出现奇怪的滞后

我正在写一个交stream程序,通过tcp连接发送一个bash shell的输出。 为了让我的程序更具响应性,我使用setsockopt()来启用TCP_NODELAY,它禁用了Nagle的缓冲algorithm。 这工作很好,除非很less有大消息滞后。 如在,如果消息超过大约500字节(可能是512)。 前500个字节会通过(快速地在小信息中),然后在1-2秒内延迟,其余的一次被接收。 这只发生一次,每10-15次收到一个大消息。 在服务器端,消息一次一个字节地写入套接字,并且所有的字节都可用,所以这种行为对我来说是意想不到的。

我最好的猜测是,有一个512字节的缓冲区在sockets的某个地方导致一个块? 我做了一些时间testing,看看滞后在哪里,我非常确定这是发生滞后的套接字本身。 服务器端的所有数据都是无阻塞地写入的,但客户端收到滞后后的消息结束。 但是我使用getsockopt()来查找套接字的接收和发送缓冲区,它们分别大于512字节 – 66000和130000。 在客户端,我使用express js来接收处理程序中的数据(app.on('data',function(){}))。 但是我读到这个expression函数不会缓冲数据?

有人会猜测为什么会发生这种情况吗? 谢谢!

由于TCP_NODELAY意味着尽可能快地将每一条数据作为一个数据包发送,而不必将数据合并在一起,这听起来像是在发送大量数据包。 由于您一次只写一个字节,因此只能发送一个字节的有效负载和更大的帧。 这在大多数情况下都能正常工作,但是只要第一个数据包因为某种原因而下降,接收器就需要在TCP套接字上进入纠错模式,要求重新传输丢弃的数据包。 这将导致至less一个往返延迟,也许几个。 这听起来像是你前几百个数据包(500字节值)幸运,然后通常打你的第一个数据包下降,由于纠错减缓下降。 一个简单的解决scheme可能是写入较大的数据块,例如一次写入10个字节,而不是1个字节,这样可以减less丢失数据包的几率。 那么你会希望看到这个问题的频率只有5000字节左右。 通常情况下,设置TCP_NODELAY会使事情一开始就会变得更快,但是由于TCP_NODELAY不会减less每个数据量发送的数据包的数量,所以只需要尽快结束第一个丢弃的数据包。 因此,它增加或保留了相同的数据包数量,这意味着在一定数量的数据内击中丢包的机会将会增加。 互动的感觉和第一次打嗝之间有一个权衡。 通过避免TCP_NODELAY,您可以延迟平均在第一次错误重新传输之前发送的典型数据量。

使用tcpdump或wire-shark获取networking捕获。 查看包传输时间线,这将有助于区分networking问题和软件实施问题。 如果您看到重新传输,您可能会遇到networking问题,如果您发现缓慢的问题,您可能会发现最好不要使用“无延迟”,因为Ack延迟会阻止“无延迟”连接。