繁体   English   中英

TCP套接字发送缓冲区大小的效率

[英]TCP Sockets send buffer size efficiency

当使用WinSock或POSIX TCP套接字(在C / C ++中,因此不需要额外的Java / Python /等包装)时,在用户空间中建立更大的缓冲区(例如,最大4KB)是否有任何效率方面的利弊,然后发送尽可能少的调用来发送该缓冲区与直接使用数据位(例如1-1000字节)进行多个较小的调用,其他事实是,对于非阻塞/异步套接字,单个缓冲区对我来说可能更容易管理。

我知道不建议使用recv小缓冲区,但找不到任何要发送的东西。

例如,每个在通用平台上的发送呼叫都进入内核模式吗? 1字节发送是否会导致正常情况下发送1字节数据包?

正如Richard Stevens在TCP Illustrated Vol I上所解释的那样,TCP将发送缓冲区划分为接近最佳段的长度,以适应沿着通往另一个TCP对等方的路径的最大数据包大小。 这意味着它将永远不会尝试将被ip分割的段沿着到目的地的路由发送(当数据包在某个ip路由器上被分割时,它会发回IP碎片ICMP数据包,而TCP将考虑它以减少此连接的MSS)。 就是说,不需要更大的缓冲区,就不会比路径上的链路​​级接口的最大包大小大。 假设有一个或两次或更长时间,则可以确保TCP不会在收到对远程对等方的某些确认后立即停止发送,因为它的缓冲区中没有数据。

认为普通接口类型是以太网,并且最大数据包大小为1500字节,因此通常TCP不会发送大于此大小的段。 而且它通常每个连接都有一个8Kb的内部缓冲区,因此在内核空间中增加缓冲区大小没有什么意义(如果这是在内核空间中具有缓冲区的唯一原因)。

当然,还有其他一些因素迫使您在用户空间中使用缓冲区(例如,您要存储数据以发送到对等进程的某个位置,因为内核空间中只有8Kb数据需要缓冲,因此您需要有更多空间可以执行其他一些进程)例如:ircd(Internet中继聊天守护程序)在断开连接之前使用了高达100Kb的写缓冲区,因为另一侧没有接收/确认该数据。 如果仅对连接写入(2) ,则一旦内核缓冲区已满,您将被等待,也许这不是您想要的。

在用户空间中具有缓冲区的原因是因为TCP也进行流控制,因此当它无法发送数据时,必须将其放置在某个地方以对其进行处理。 您必须决定是否需要将数据保存到最大限制的过程,或者可以阻止发送数据,直到接收者可以再次接收为止。 内核空间中的缓冲区大小是有限的,通常对于用户/开发人员来说是无法控制的。 用户空间中的缓冲区大小仅受其允许的资源限制。

不建议在TCP连接中接收/发送小块数据,因为TCP握手和标头会增加开销。 假设一个telnet连接 ,其中为每个发送的字符添加一个TCP报头和另一个IP报头(TCP至少20个字节,IP至少20个字节,以太网帧至少14个字节,以太网CRC 4个),总共为60字节+仅发送一个字符。 而且通常每个tcp段都是单独确认的,因此要花费一个完整的往返时间来发送一个段并获得确认(只是为了释放缓冲区资源并假定此字符已被传输)

那么,最后有什么限制? 这取决于您的应用程序。 如果您可以应付可用的内核资源并且不需要更多的缓冲区,则可以在用户空间中没有havin缓冲区的情况下进行传递。 如果您需要更多,则需要实现缓冲区并能够在可用时将缓冲区数据与内核缓冲区一起提供。

是的,一个字节的send可以-非常正常的条件下-导致发送TCP数据包只有一个字节的有效载荷。 TCP中的发送合并通常是使用Nagle算法完成的 使用Nagle的算法,如果存在已发送但尚未确认的数据,则延迟发送数据。

相反,如果没有未确认的数据,将立即发送数据。 在以下情况下通常是这样:

  • 连接刚刚打开
  • 连接已闲置了一段时间
  • 连接仅接收数据,但一段时间未发送任何内容

在这种情况下,您的应用程序执行的第一个send调用将导致立即发送一个数据包,无论它的大小如何。 因此,使用两个或多个小send通信通常是一个坏主意,因为这会增加开销和延迟。

臭名昭著的“发送发送接收”模式也可能导致很大的延迟(例如,在Windows上通常为200ms)。 如果本地TCP堆栈使用Nagle算法(通常会延迟第二个发送),而远程堆栈使用延迟的确认 (这可能会延迟第一个数据包的确认),则会发生这种情况。

由于大多数TCP堆栈实现都同时使用Nagle的算法延迟的确认,因此最好避免这种模式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM