谁将TCP窗口大小设置为0,是Indy还是Windows?

6
我们有一个应用服务器,观察到在网络拥塞时(在客户端的现场),发送带有TCP窗口大小为0的标头。我们想知道是Indy还是底层Windows层负责将TCP窗口大小从名义64K调整为适应可用吞吐量的大小。当它变为0时,我们将能够采取行动(没有数据发送,用户等待=>不好)。因此,任何信息、链接或指向Indy代码的指针都是受欢迎的...免责声明:我不是网络专家。请保持答案易于理解平均我;-)注意:它是Indy9/D2007在Windows Server 2003 SP2上。更多详细信息:TCP零窗口情况发生在中间层与DB服务器通信时。它发生在最终用户抱怨客户端应用程序减速的同一时刻(这就引发了网络调查)。已经确定了两个导致瓶颈的主要网络问题。TCP零窗口发生在网络拥塞时,但可能并非由其引起。我们想知道何时发生,并在我们的代码中有一种方法(至少记录)。所以核心问题是谁设置窗口大小为0,以及在哪里?在哪里挂钩(在Indy中?)以了解何时发生该条件?
3个回答

7
TCP头部中的窗口大小通常由TCP堆栈软件设置,以反映可用缓冲区空间的大小。如果您的服务器发送带有零窗口设置的数据包,则可能是因为客户端发送数据的速度比运行在服务器上的应用程序读取它的速度更快,与TCP连接关联的缓冲区现在已满。
如果客户端发送数据比服务器读取数据的速度快,则TCP协议的这种正常操作。客户端应该等待服务器发送非零窗口大小后再发送数据(没有意义,因为它将被丢弃)。
这可能反映出客户端和服务器之间的严重问题,也可能不是,但如果该条件持续存在,则可能意味着运行在服务器上的应用程序已停止读取接收到的数据(一旦开始读取,这将释放TCP的缓冲区空间,并且TCP堆栈将发送新的非零窗口大小)。

核心问题是谁将窗口大小设置为0以及在哪里?更新问题... - Francesca
3
TCP协议栈(在这种情况下,是Windows Server的一部分)将窗口大小设置为零,但这是因为运行在服务器上的应用程序(Indy?)没有读取数据。 - Stephen C. Steel
所以,如果中间层由于网络拥堵而无法向客户端应用程序传递数据,则可能会停止读取来自DB服务器的数据,这将导致操作系统将TCP窗口大小设置为0...然后每个人都等待事情变得更好。对吧? - Francesca
@Stephen C. Steel:Indy是随Delphi一起提供的通信库(TCP、IP、HTTP等)。 - Francesca
@Francois 由于服务器发送TCP数据包时窗口大小为零,因此是服务器应用程序未能像客户端发送数据一样快速读取(而不是反过来)。至于为什么服务器没有读取,我无法帮助您 - 这取决于有关您的服务器应用程序的详细信息,而我不熟悉它。 - Stephen C. Steel
@Stephen C. Steel,感谢您的所有解释。 - Francesca

2

如果您对解决问题感兴趣:

如果您可以控制发送0窗口大小消息的服务器端上运行的内容,是否考虑使用setsockopt()和SO_RCVBUF显著增加套接字接收缓冲区的大小?

在Indy中,setsockopt()是TIdSocketHandle的一种方法。您应该将其应用于与您的套接字相关联的所有TIdSocketHandle对象。在Indy 9中,这些对象位于属性Bindings中的TIdTCPServer。

我建议首先使用getsockopt()和SO_RCVBUF查看操作系统提供的默认缓冲区大小。然后显著增加缓冲区大小,每次都可以通过逐步试验来加倍缓冲区大小。您可能还想在setsockopt()之后重新运行getsockopt()调用以确保实际执行了setsockopt():通常,套接字实现会将缓冲区大小设置为上限值。在这种情况下,通常有一种依赖于操作系统的方法来提高上限值。但这些是相当极端的情况,您不太可能需要这样做。

如果您无法控制溢出的源代码,请检查运行在那里的软件是否公开了更改缓冲区大小的参数。

祝好运!


感谢您提供这个非常有价值的信息。 - Francesca

2
TCP头部的窗口大小为0表示接收方的缓冲区已满。对于写入速度比读取速度快的情况,这是一种正常的状态。
阅读你的描述,不清楚这是否出乎意料。是什么导致你打开了协议分析器?

有几个或那里的问题似乎不是问题,但当它发生时,同一秒钟内就会出现40个。当最终用户抱怨客户端应用程序明显变慢时,调查就开始了。在网络层识别出了两个主要问题,这可能会导致瓶颈。但TCP零窗口可能与这些条件有关,也可能不是,无论如何,我们希望在其发生时能够意识到并至少记录一些信息。 - Francesca

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