来自文档:
当 NoDelay 为 false 时,TcpClient 不会通过 网络,直到收集到大量传出数据。 由于 TCP 段中的开销量,发送小 数据量大,效率低下。然而,确实存在这样的情况:您 需要发送非常少量的数据或期望立即响应 从您发送的每个数据包中。您的决定应该权衡相关因素 网络效率与应用程序需求的重要性。
在这种情况下有多少字节符合
small amounts of data
?
根据我的理解,如果您有一个
NetworkStream
,每个请求从TcpClient
写入一次TCP流(即不是以循环或分块方式),然后立即刷新,那么NoDelay
并不重要,基于约翰·内格尔的回应。当 NoDelay
未设置写入时,DotNet 中的延迟是多少?
这仍然让我烦恼。真正的问题不是tinygram的预防。它是 ACK 延迟,还有那个愚蠢的固定计时器。他们都进入了TCP 大约在同一时间,但独立。我做了tinygram预防 (Nagle 算法)和 Berkeley 确实延迟了 ACK,两者都在早期 20 世纪 80 年代。两者的结合是可怕的。不幸的是到时候 我发现了延迟的 ACK,我换了工作,脱离了网络, 并在非联网 PC 上为 Autodesk 开发产品。延迟的 ACK 仅在某些情况下才是胜利 - 主要是角色回声 远程登录。 (当伯克利安装延迟 ACK 时,他们做了很多 从学生终端室的终端集中器到 Telnet 主机 VAX 机器进行工作。针对这种特殊情况, 是有道理的。)延迟的 ACK 定时器被缩放到预期的人类 响应时间。延迟的 ACK 是指另一端会回复的赌注 您刚刚发送的内容几乎是立即发送的。除了一些RPC协议之外, 这不太可能。所以ACK延迟机制输了赌注,结束了 结束,延迟 ACK,等待可以收到 ACK 的数据包 捎带,没有收到,然后发送 ACK,延迟了。 TCP 中没有任何内容可以自动关闭此功能。然而,Linux (我认为 Windows)现在有一个 TCP_QUICKACK 套接字选项。转动那个 除非您有非常不寻常的应用程序。
开启 TCP_NODELAY 有类似的效果,但可以使吞吐量 对于小写入来说更糟。如果你编写一个只发送一些数据的循环 使用“write()”将字节(最坏情况,一个字节)发送到套接字,并且 Nagle 使用 TCP_NODELAY 禁用算法,每次写入都会变成一个 IP 包。这使 IP 和 TCP 的流量增加了 40 倍 每个有效负载的标头。 Tinygram 预防不会让您发送 第二个数据包(如果您在飞行中有一个数据包),除非您有足够的数据 填充最大尺寸的数据包。它累积一轮的字节数 行程时间,然后发送队列中的所有内容。几乎总是这样 你想要什么。如果设置了 TCP_NODELAY,则需要做更多 了解缓冲和刷新问题。
这些对于批量单向传输来说都不重要,这是大多数 HTTP 今天。 (我从来没有研究过这对 SSL 握手的影响, 这可能很重要。)
简短版本:设置 TCP_QUICKACK。如果你发现这样的情况 事情更糟,请告诉我。
约翰·内格尔
当
NoDelay
在发送方发送时,接收方还可以进行哪些其他与 TCP 相关的优化,以在低延迟环境中尽可能高效地接收小尺寸数据(500 字节 - 2 KB)?
归结为数据是否大于MTU(TCP发送数据包大小)。如果数据多于此(或者没有未确认的已发送数据包),则将立即发送数据,否则将进行缓冲,直到达到 MSS。 MSS 通常为 1500 字节,扣除 40 字节的开销后,MTU 为 1460 字节。
NetworkStream.Flush
什么也没做:
方法实现了Flush
方法;但是,由于Stream.Flush
没有缓冲,因此对网络流没有影响。调用NetworkStream
方法不会引发异常。Flush
所以你调用它没有什么区别。除非使用
TCP_NODELAY
禁用,否则将使用 Nagles 算法。
除了平常没有什么:
async
代码。至于您的引用:
TCP_QUICKACK
很可能比TCP_NODELAY
更好,但我建议您根据您的典型用法进行测试。