TCP ACK响应延迟10ms



我正在编写一个客户端应用程序,该应用程序应该从服务器接收文件。通信使用了一个通过TCP设计的非常简单的专有协议:服务器发送一个16KB的数据块,等待我的客户端的简单响应,然后进入下一个数据块;这样做直到文件被完全传输。

服务器正在Windows上运行。如果我在Windows上运行我的客户端(通过Cygwin),我可以实现70Mbits/s的吞吐量。但是,如果我在Linux上运行它,我可以获得的最大吞吐量是5Mbits/s(两个测试都使用相同的100Mb以太网链路)。

在对我收集的tcpdump跟踪进行了一些调查之后,我发现Linux大约需要10ms来回答每个TCP ACK。每次调用recv()后,我都试图禁用sockpoption TCP_REQUICKACK,但没有成功。我没有发现任何其他TCP选项可以改变这种行为(在bsd套接字下,甚至在Linux下)。

有人能帮我弄清楚发生了什么事吗?

  1. 我的客户端是用C++编写的,使用BSD套接字。TCP_NODELAY sockpoption已在其上设置
  2. 我的linux内核是2.6.19
  3. 专有协议和服务器不是我的,所以我不能以任何方式更改它们

下面是我分析的tcpdump跟踪的一个示例。这是一个区块传输。服务器IP为10.200.252.1,客户端为10.200.252。以**开始的线路是具有10ms延迟的TCP ACK数据包:

   5184 28.060969   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4736738 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5185 28.060978   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4738182 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5186 28.060981   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4739626 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5187 28.060987   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4741070 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5188 28.060990   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4742514 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5189 28.060994   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4743958 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5190 28.060997   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4745402 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5191 28.061000   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4746846 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5192 28.061003   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4748290 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5193 28.061007   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4749734 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5194 28.061038   10.200.252.1          10.200.252.2          TCP      1510   search-agent > 58358 [ACK] Seq=4751178 Ack=1741 Win=66048 Len=1444 TSval=2951472 TSecr=2921060
   5195 28.061042   10.200.252.1          10.200.252.2          TCP      572    search-agent > 58358 [PSH, ACK] Seq=4752622 Ack=1741 Win=66048 Len=506 TSval=2951472 TSecr=2921060
 **5196 28.068422   10.200.252.2          10.200.252.1          TCP      66     58358 > search-agent [ACK] Seq=1741 Ack=4742514 Win=64512 Len=0 TSval=2921061 TSecr=2951472
 **5197 28.078479   10.200.252.2          10.200.252.1          TCP      66     58358 > search-agent [ACK] Seq=1741 Ack=4753128 Win=64512 Len=0 TSval=2921062 TSecr=2951472
   5198 28.082418   10.200.252.2          10.200.252.1          TCP      70     58358 > search-agent [PSH, ACK] Seq=1741 Ack=4753128 Win=64512 Len=4 TSval=2921062 TSecr=2951472
   5199 28.082675   10.200.252.2          10.200.252.1          TCP      68     58358 > search-agent [PSH, ACK] Seq=1745 Ack=4753128 Win=64512 Len=2 TSval=2921062 TSecr=2951472
   5200 28.082714   10.200.252.1          10.200.252.2          TCP      66     search-agent > 58358 [ACK] Seq=4753128 Ack=1747 Win=66048 Len=0 TSval=2951474 

完全去掉分块和应用程序ACK。如果必须的话,只需在文件末尾放一个最后一个即可。TCP已经进行了分块和ACK,而你正在把它逼疯,例如,它必须对ACK进行ACK。没有必要这么复杂。这是一个流媒体协议:像使用它一样。

最新更新