使用WinSock或POSIX TCP套接字(在C / C ++中,所以没有额外的Java / Python /等包装),在用户中构建更大的缓冲区(例如说高达4KB)是否有任何效率利弊空间然后尽可能少地发送调用以发送该缓冲区与直接使用数据位(比如1-1000字节)进行多个较小的调用,另外,对于非阻塞/异步套接字,单个缓冲区可能是我更容易管理。
我知道不推荐使用recv小缓冲区,但我找不到任何发送内容。
e.g。每个在公共平台上发送呼叫都会进入内核模式吗? 1字节发送实际上是否会导致在正常条件下传输1字节数据包?
答案 0 :(得分:1)
正如理查德史蒂文斯在 TCP Illustrated Vol I 中所解释的那样,TCP将发送缓冲区分成近似最佳段,以适应沿着到另一个TCP对等体的路径的最大数据包大小。这意味着它永远不会尝试发送将通过ip分段到达目的地的路段(当某个数据包在某个IP路由器上分段时,它会发回一个IP分片ICMP数据包,而TCP会将其考虑在内以减少此连接的MSS)。也就是说,不需要比路径上的链路级接口的最大数据包大小更大的缓冲区。拥有一个,比如说,两次或三次更长,确保TCP在收到远程对等体的一些确认后不会立即停止发送,因为没有缓冲区填充数据。
认为普通接口类型是以太网,并且它的最大数据包大小为1500字节,因此通常TCP不会发送大于此大小的段。它通常每个连接都有一个8Kb的内部缓冲区,因此在内核空间中添加缓冲区大小没有什么意义(如果这是拥有缓冲区的唯一原因)在内核空间)。
当然,还有其他因素会迫使您在用户空间中使用缓冲区 (例如,您希望将数据存储到某个地方的同级进程中,因为那里有'在内核空间中只有8Kb数据要缓冲,并且你需要更多空间才能做其他一些进程。例如:ircd(Internet Relay Chat守护进程)在删除连接之前使用最多100Kb的写缓冲区,因为另一个方未接收/确认该数据。如果你只对连接写(2),那么一旦内核缓冲区已满,你就会等待,也许这不是你想要的。
在用户空间中使用缓冲区的原因是因为TCP也可以进行流量控制,因此当它无法发送数据时,必须将其放在某处以应对它。您必须决定是否需要您的过程将数据保存到一个限制,或者您可以阻止发送数据,直到接收器能够再次接收为止。内核空间中的缓冲区大小是有限的,通常对用户/开发人员来说是无法控制的。用户空间中的缓冲区大小仅受允许的资源限制。
由于TCP握手和标头强加的开销增加,不建议在TCP连接中接收/发送小块数据。假设 telnet连接,其中对于每个发送的字符,添加TCP和其他IP的标头(TCP为20字节,IP为20字节,以太网帧为14字节,4为以太网CRC)最多60个字节+,只传输一个字符。通常每个tcp段都是单独确认的,这样就可以完整的往返时间来发送一个段并获得确认(只是为了能够释放缓冲区资源并假设这个字符被传输)
所以,最后,限制是什么?这取决于您的应用程序。如果您可以处理可用的内核资源并且不需要更多缓冲区,则可以在用户空间中不使用havin缓冲区。如果您需要更多,则需要实现缓冲区,并且能够在可用时向内核缓冲区提供缓冲区数据。
答案 1 :(得分:0)
是的,在非常正常的条件下,一个字节send
可能导致发送仅包含单个字节有效载荷的TCP数据包。 TCP中的发送合并通常是使用Nagle's algorithm完成的。使用Nagle的算法,如果有已发送但尚未确认的数据,则发送数据会延迟。
相反,如果没有 个未确认的数据,则将立即发送数据。在以下情况下通常是这样:
在这种情况下,您的应用程序执行的第一个send
调用将导致立即发送一个数据包,无论大小如何。因此,开始与两个或更多小的send
进行通信通常是一个坏主意,因为这会增加开销和延迟。
臭名昭著的“发送发送接收”模式也会导致很大的延迟(例如,在Windows上通常为200ms)。如果本地TCP堆栈使用Nagle的算法(通常会延迟第二个发送),而远程堆栈使用delayed acknowledgment(会延迟第一个数据包的确认),则会发生这种情况。
由于大多数TCP堆栈实现同时使用Nagle的算法和延迟确认,因此最好避免这种模式。