TCP本身属面向链接的通讯协议。通讯双方的每一个收发动作,需要以通讯链路正常为前提。因此TCP协议内部提供了默认的ACK验证机制。
而ACK验证方式存又与操作系统有关,在TCP中,对数据的确认往往是延迟的,在时延定时器没有溢出的情况下,一般情况是两个TCP数据对应一个确认,如果时延定时器溢出了,那么自然也会发送确认报文。
但在某些系统中,会出现必须每次回复ACK包才继续发送TCP数据,这时就会出现以下问题:假定Server A、和Client B之间建立了一个TCP连接,某一时刻A第一次向B发送数据,发送完成后等待B回复的ACK包,而B认为收到第二个TCP数据包才回复ACK标记,则约200ms之后,B中的时延定时器溢出,B此时才向A回发一个长度为1的ACK确认包,因此B第二次收到数据时,会莫名其妙的产生一个约200ms的延时--这个延时不是别的,正是ACK确认包默认的发送时延。
当我们测试自行研发的服务端通讯框架时,一旦其发生广播,则此时处于接收方的客户端很有可能会因为通讯双方的收发不均而引发上述现象--这并非是由于你的服务端通讯框架性能不达标,而是由于TCP的内部机制导致的。
那么,我们应该如何避免这种情况呢?这里介绍一种最简单也最容易实现的方法--修改注册表,提高客户端ACK包默认的发送频率,也就是缩短ACK包的发送时延:
首先,点击你电脑屏幕左下角的"开始"菜单,打开"运行",键入"regedit"打开你的注册表;
选择HKEY_LOCAL_MACHINE 项目开始一层层的往下点,一直到
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces
这里是关于你网卡的数据,有很多项,且它们都有类似{5F26EBBD-9CA6-4219-9DBD-54852364EA17}这样的名字,但是正确的那个会在右边窗口显示包括你的IP地址和你的服务器IP地址等等网络设定)。 你找到IPAddress项符合你的本机IP地址的那个,那么它就是你连接网络的那个网卡的设定项,我们的任务目标就是改动它来提高客户端ACK包的发送频率。
其次,右键点击窗口右边的空白处,"新建"-"DWORD值";
给它改名成"TcpAckFrequency",然后右键点击它 ,选择"修改",然后再那个"数值数据"的空白处填"1"(不用管是16进制,还是10进制)
最后,关闭注册表,重启电脑,修改完成。
有关TcpAckFrequency的补充说明:
TcpAckFrequency 值这个值确定了windows用TCP/IP 发送应答消息的频率,也就是决定了在发送"命令正确应答"之前将等候几个数据包;
默认值为 2,这时TCP/IP 将在接收到 2 个分段后发送应答,或是在接收了 1 个分段但在 200 毫秒内没有接收到其他分段的情况下发送应答
如果值为 3,则 TCP/IP 将在接收到 3 个分段后发送应答,或是在接收了 1 个或 2 个分段但在 200 毫秒内没有接收到其他分段的情况下发送应答,以此类推。
如果需要通过消除 TCP/IP 应答延迟来缩短响应时间,则将该值设为 1.在这种情况下,Windows将每收到一个TCP数据包就回送一个"命令正确应答".
该值的有效范围是 0 到 255,其中 0 表示使用缺省值(2)。
采用Delayed ACK机制后,通常是服务端发送2个数据包后,客户端再进行确认,这样将极大的减少不必要的ACK数据包,同时也能提高访问速度,减少带宽浪费。
修改方法:
在注册表中添加键值进行修改;
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/TcpipParameters/InterfacesAdapter/ GUID
值名称:TcpDelAckTicks(不同的操作系统该值的名称不尽相同)
数据类型:REG_DWORD
值数据:将该值设置为 0 到 6 之间的值
默认情况下,延迟 ACK 计时器值为 200 毫秒。如果将 TcpDelAckTicks 值设置为 0,则禁用延迟确认。
当然,以上处理是能够解决问题的。不过既然知道原因了,就可以修改板子上的TCP的数据传输的实现,可以一次传输两个包到PC,这样就可以避免去设置默认的注册表值了。