【问题标题】:Strange lag when sending large message using tcp_nodelay使用 tcp_nodelay 发送大消息时出现奇怪的延迟
【发布时间】:2015-07-09 16:40:31
【问题描述】:

我正在编写一个通过 tcp 连接发送 bash shell 输出的 c 程序。为了使我的程序响应更快,我使用 setsockopt() 来启用 TCP_NODELAY,这会禁用 Nagle 的缓冲算法。这很好用,除了很少有大消息的滞后。如,如果消息超过大约 500 个字节(可能是 512)。前 500 个字节将通过(在小消息中很快),然后将有 1-2 秒的延迟,然后一次全部接收到其余字节。这种情况每收到 10 到 15 次大消息就会发生一次。在服务器端,消息一次一个字节地写入套接字,并且所有字节都可用,所以这种行为对我来说是意料之外的。

我最好的猜测是套接字中某处有一个 512 字节的缓冲区导致阻塞?我做了一些时间测试来查看滞后在哪里,我很确定这是发生滞后的套接字本身。服务端的所有数据都是在没有阻塞的情况下写入的,但是客户端在延迟之后才收到消息的结尾。但是,我使用 getsockopt() 来查找套接字的接收和发送缓冲区,它们远远超过 512 个字节 - 分别为 66000 和 130000。在客户端,我使用 express js 在处理程序(app.on('data', function(){}))中接收数据。但是我读到这个 ​​express 函数不缓冲数据?

有人能猜出为什么会这样吗?谢谢!

【问题讨论】:

    标签: c node.js sockets tcp


    【解决方案1】:

    由于 TCP_NODELAY 意味着尽快将每条数据作为一个数据包发送而不将数据组合在一起,因此听起来您正在发送大量数据包。由于您一次写入一个字节,因此它可以发送只有一个有效负载字节和更大帧的数据包。这在大多数情况下都可以正常工作,但是一旦第一个数据包由于某种原因丢失,接收器就需要进入 TCP 套接字上的纠错模式以请求重新传输丢失的数据包。这将导致至少一个往返延迟,也许还有几个。听起来您对前几百个数据包(价值 500 字节)很幸运,然后通常会遇到第一个数据包丢失并由于纠错而减慢速度。一个简单的解决方案可能是写入更大的块,比如一次 10 个字节,而不是 1 个字节,这样命中丢弃数据包的机会就会小得多。然后你会期望看到这个问题的频率和你只看到大约 5000 字节左右的消息一样。一般来说,设置 TCP_NODELAY 会导致事情开始变得更快,但最终会更快地击中第一个丢弃的数据包,因为 TCP_NODELAY 不会减少每数据量发送的数据包数量。因此,它会增加或保持相同的数据包数量,这意味着您在一定数量的数据中命中丢弃数据包的机会将会增加。在交互感觉和第一次打嗝之间有一个权衡。通过避免 TCP_NODELAY,您可以在平均命中第一个错误重传之前延迟将要发送的典型数据量。

    【讨论】:

    • 感谢您的详细解答!这很有帮助!
    • 听取您的建议,并在可能的情况下大写 - 现在效果很好,再次感谢!!
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-24
      • 1970-01-01
      • 2019-05-16
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      相关资源
      最近更新 更多