增大TCP窗口大小。

15

我对在应用程序中增加TCP窗口大小有一些疑问。在我的C++软件应用程序中,我们使用TCP/IP阻塞套接字从客户端向服务器发送大约1k大小的数据包。最近我了解到了TCP窗口大小这个概念。因此,我尝试使用setsockopt()将值增加到64K,同时使用SO_SNDBUFSO_RCVBUF。增加这个值后,我在WAN连接中获得了一些性能改进,但在LAN连接中没有。

根据我的理解,在TCP窗口大小中,

客户端将数据包发送到服务器。当达到此TCP窗口大小时,它将等待确保服务器收到窗口大小中第一个数据包的ACK。在WAN连接的情况下,由于RTT约为100ms的延迟,ACK从服务器到客户端的接收会被延迟。因此,在这种情况下,增加TCP窗口大小可以补偿ACK等待时间,从而提高性能。

我想了解如何改进我的应用程序性能。

在我的应用程序中,尽管使用setsockopt在套接字级别上增加了TCP窗口大小(发送和接收缓冲区),但我们仍然保持相同大小的数据包(即我们在单个套接字发送的字节数为1k)。同时,我们禁用了Nagle算法(内置选项,将小数据包合并成大数据包,从而避免频繁的套接字调用)。

我的疑问如下:

  1. 由于我使用的是阻塞套接字,对于每个大小为1k的数据包发送,如果没有收到来自服务器的ACK,它应该被阻塞。那么,在WAN连接中增加TCP窗口大小后,性能如何提高?如果我误解了TCP窗口大小的概念,请纠正我。

  2. 对于发送64K的数据,我认为即使我将TCP窗口大小增加到64K,仍然需要调用64次套接字发送函数(因为我正在通过阻塞套接字每次发送1k)。请确认这一点。

  3. 启用RFC 1323算法的窗口缩放后TCP窗口大小的最大限制是多少?

我英语不是很好。如果您无法理解上述内容,请告知我。


TCP 可以动态更改分段大小以匹配任何路由器的最高 max-MTU,以优化性能。当您不希望发生这种情况时,可以通过设置“不分段”标志来防止这种情况发生。 - Philipp
2个回答

35
首先,您的问题存在一个很大的误解:TCP窗口大小是由SO_SNDBUFSO_RCVBUF控制的。这是不正确的。
TCP窗口大小是什么?
简而言之,TCP窗口大小确定了在接收到尚未确认的最早数据包之前,您的网络堆栈愿意将多少后续数据(数据包)放在线路上。
TCP堆栈必须考虑并解决以下事实:一旦确定在传输过程中丢失或损坏了数据包,则从那个数据包开始发送的每个数据包都必须重新发送,因为接收者只能按顺序确认数据包。因此,允许太多未确认的数据包同时存在会“投机地”占用连接的带宽:不能保证使用的带宽实际上会产生任何有用的东西。
另一方面,不允许同时存在多个未确认的数据包将简单地耗尽高带宽延迟乘积连接的带宽。因此,TCP堆栈必须在使用带宽而没有任何好处和不足够积极地驱动管道之间取得平衡(从而允许部分容量未使用)。
TCP窗口大小决定了这种平衡点在哪里。 SO_SNDBUFSO_RCVBUF做什么?
它们控制网络堆栈为服务您的套接字保留的缓冲区空间的数量。这些缓冲区用于累积尚未能够放入电线上的传出数据以及已从电线上接收但尚未被应用程序读取的数据。
如果其中一个缓冲区已满,则无法发送或接收更多数据,直到释放一些空间。请注意,这些缓冲区仅影响网络接口“附近”侧上的数据(在发送或到达之前),而TCP窗口则影响堆栈在接口的“远”侧上管理数据的方式(即在线路上)。
您的问题的答案
  1. 不行。如果是这样,那么每发送一个数据包都会产生往返延迟,这将完全破坏高延迟连接的带宽。

  2. 可以,但这与TCP窗口大小或分配给该套接字的缓冲区大小无关。

  3. 根据我所能找到的所有来源(example),扩展允许窗口达到最大1GB的大小。


@Prabu:套接字级别无法设置窗口大小,窗口大小适用于整个连接。此外,Vista引入了管理连接的重大变化(整个堆栈被重新编写)。 - Jon
1
@Prabu:该页面上写着“如果缓冲区太小,TCP窗口无法完全打开,这会限制性能”。请注意,缓冲区大小是固定的,而窗口是“打开”的,因此它们不能是同一件事。但是,缓冲区大小确实限制了窗口的最大大小:数据包在被确认之前会留在缓冲区中。如果缓冲区已满,我们可能愿意发送更多未经确认的数据(增加窗口),但没有地方存放它们,因此窗口永远不能比缓冲区更大。 - Jon
1
@Jon,确实如此。最大动态窗口大小由目标端的套接字接收缓冲区大小和生效的窗口缩放确定。根据套接字接收缓冲区中任何时刻剩余的空间量,动态窗口大小会向下调整。这种关系非常紧密。(b)“接口窗口”这种说法是不存在的,它是每个连接的值。 - user207421
@EJP:我可能没有记住细节,让我恢复一下,然后回答。 - Jon
暂且不谈窗口缩放,当前广告窗口大小等于套接字接收缓冲区中当前可用空间的大小。 - user207421
显示剩余3条评论

1
由于我使用的是阻塞式套接字,每次发送1k的数据包时,如果未收到服务器的ACK,则应该阻塞。

错误。在TCP发送中是异步的,send()仅将数据传输到套接字发送缓冲区并返回。只有在套接字发送缓冲区已满时才会阻塞。

因此,在WAN连接中改进TCP窗口大小后,性能如何改善?

因为你错了关于它等待ACK的想法。

对于发送64K的数据,您认为我仍需要调用socket send函数64次吗?

为什么?您可以只调用一次,并使用64k数据缓冲区。

(因为我通过阻塞套接字每次发送1k)

为什么?还是这是您在(1)下误解的重复?

即使我将TCP窗口大小增加到64K,也不能一次性发送所有数据。请确认此事。

不。您可以一次性发送所有数据,无需循环。

TCP窗口大小的最大限制是启用RFC 1323算法的窗口缩放后是多少?

远远超出你所需的范围。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接