我正在编写一个通过tcp连接发送bash shell输出的c程序。为了使我的程序更具响应性,我使用setsockopt()来启用TCP_NODELAY,这会禁用Nagle的缓冲算法。这很有效,除了很少有大量消息的延迟。如同,如果消息超过大约500字节(可能是512)。前500个字节将经过(快速在小消息中),然后在一次全部接收其余部分之前将延迟1-2秒。这仅在每10-15次收到大消息时发生一次。在服务器端,消息正在一次一个字节地写入套接字,并且所有字节都可用,因此这种行为对我来说是意外的。
我最好的猜测是套接字中的某个地方有一个512字节的缓冲区导致阻塞?我做了一些时间测试,看看滞后的位置,而且我很确定它是发生滞后的插座本身。服务器端的所有数据都是在没有阻塞的情况下写入的,但客户端会在延迟后收到消息的结尾。但是我使用getsockopt()来查找套接字的接收和发送缓冲区,它们分别超过512字节--66000和130000。在客户端,我使用快速js在处理程序中接收数据(app.on(' data',function(){}))。但我读到这个express函数不缓冲数据?
有人会猜到为什么会这样吗?谢谢!
答案 0 :(得分:2)
由于TCP_NODELAY意味着尽快将每个数据作为数据包发送而不将数据组合在一起,这听起来像是在发送大量数据包。由于您一次只写一个字节,因此它可以发送只有一个字节有效负载和更大帧的数据包。这在大多数情况下都能正常工作,但是一旦第一个数据包因任何原因而丢失,接收器就需要在TCP套接字上进入纠错模式,要求重新传输丢弃的数据包。这将导致至少一次往返延迟,也许会产生几次。这听起来好像您前几百个数据包(500个字节值)的幸运,然后通常会因为纠错而击中您的第一个数据包丢失并减慢速度。一个简单的解决方案可能是写入更大的块,比如说一次10个字节,而不是1个字节,这样就可以更少地击中丢弃的数据包。然后,您可能会经常看到此问题,因为您只对大约5000字节左右的消息执行此操作。一般来说,设置TCP_NODELAY会导致事情开始变得更快,但最终只是因为TCP_NODELAY不会减少每个数据量发送的数据包的数量而更快地达到第一个丢弃的数据包。因此它会增加或保留相同数据包的数量,这意味着您在一定数量的数据中击中丢弃数据包的机会将会增加。交互式感觉和第一次打嗝之间存在权衡。通过避免TCP_NODELAY,您可以延迟平均命中第一次错误重传之前将发送的典型数据量。
答案 1 :(得分:0)
使用tcpdump或wire-shark获取网络捕获。查看数据包传输时间线,这有助于区分网络问题和软件实施问题。如果您看到重新传输可能会遇到网络问题,如果您看到缓慢的问题,您可能会发现最好不要使用“无延迟”,因为Ack延迟可能会停止“无延迟”连接。