5

如果我有一个 TCP 连接以 200 KB/秒的速度传输数据,但我每秒只read()/recv()从套接字一次,那么这 200 KB 的数据同时存储在哪里?

据我所知,在将 ack 发送给发送方后,数据会离开 TCP 套接字的读取缓冲区,而且无论如何它都太小而无法容纳 200KB 的数据,同时它在哪里等待直到它可以read()/recv()由我的客户端?

谢谢!!

以下答案声称数据在被确认后立即离开 TCP 读取缓冲区,然后再被 read()/recv()d:

https://stackoverflow.com/a/12934115/2378033

“接收器的套接字接收缓冲区的大小决定了在没有确认的情况下可以传输多少数据”

难道是我的假设是错误的,数据只有在用户空间程序读取()/recv()d后才被确认?

4

3 回答 3

8

确认发送给发送者后,数据离开 TCP 套接字的读取缓冲区

不,当您通过等方式读取它时,它会离开接收缓冲区。recv(), recvfrom(), read(),

以下答案声称数据一经确认就离开 TCP 读取缓冲区

费德提克。我写了它,它肯定和绝对没有“声称”任何这样的事情。

您正在考虑发送缓冲区。当接收方确认数据时,数据会从发送方的发送缓冲区中删除。那是因为发件人现在知道它已经到达并且不再需要它来重新发送。

难道是我的假设是错误的,数据只有在用户空间程序读取()/recv()d后才被确认?

是的,您的假设是错误的,这种替代猜测也是如此。数据在到达时得到确认,并由read()/recv().

于 2013-05-13T22:59:59.690 回答
2

当数据被正确接收时,它进入 TCP 读取缓冲区并立即得到确认。这并不意味着立即发送确认,因为将确认与窗口大小更新或通过连接在另一个方向发送的数据或更多数据的确认结合起来会更有效。

例如,假设您一次发送一个字节,对应于用户的输入,而另一端有一个 50000 字节的接收缓冲区。它告诉您窗口大小为 50000 字节,这意味着您可以发送这么多字节的数据而无需进一步接收任何内容。您发送的每个数据字节都会将窗口关闭一个字节。现在接收器可以发送一个数据包确认单个字节,只要它被正确接收并进入 TCP 接收缓冲区,窗口大小为 49999 字节,因为这是接收缓冲区中剩余的空间。确认将允许您从发送缓冲区中删除字节,因为您现在知道该字节已正确接收并且不需要重新发送。然后当应用程序使用read()或从 TCP 接收缓冲区中读取它时recv()这将在缓冲区中腾出空间来接收一个额外的数据字节,因此它可以发送另一个数据包,将 TCP 窗口大小更新一个字节,以允许您再次发送 50000 字节,而不是 49999。然后应用程序可能回显字符或对数据发送一些其他响应,从而导致发送第三个数据包。幸运的是,精心设计的 TCP 实现不会这样做,因为这会产生大量开销。理想情况下,它将发送一个单独的数据包,其中包含任何向另一个方向传输的数据以及任何确认和窗口大小更新作为同一数据包的一部分。当应用程序读取数据并离开接收缓冲区时,可能会发送确认,但这可能只是触发数据包发送的事件。然而,它不会总是延迟确认,也不会无限期地延迟它;在没有其他活动的短暂超时后,它将发送任何延迟的确认。

至于接收缓冲区的大小,其中包含应用程序尚未读取的接收数据,可以使用选项进行setsockopt()控制SO_RCVBUF。默认值可能因操作系统、内存大小和其他参数而异。例如,具有高延迟的快速连接(例如卫星)可能需要更大的缓冲区,尽管这会增加内存使用。还有一个发送缓冲区 ( SO_SNDBUF),其中包含尚未传输或已传输但尚未确认的数据。

于 2013-05-13T17:31:32.680 回答
1

您的操作系统将缓冲一定数量的传入 TCP 数据。例如,在 Solaris 上,默认值为 56K,但如果预计会出现大量突发,则可以合理地将其配置为高达几 MB。Linux 的默认值似乎要小得多,但您可以在此网页上查看有关增加这些默认值的说明:http ://www.cyberciti.biz/faq/linux-tcp-tuning/

于 2013-05-13T15:42:15.983 回答