第15章 TCP数据流与窗口管理;延时确认(Delayed Ack);Nagle算法;窗口通告;滑动窗口;窗口的滑动;零窗口和TCP持续计时器

"交互式"TCP连接是指该连接需要在客户端和服务器之间传输用户输入信息,如按键操作、短消息、操作杆、鼠标的动作等。
每个输入的字符会生成4个TCP报文段:客户输入字符的发送,服务端回复ack;服务端回显数据发送,客户端回复ack
  服务端通常会将2,3段报文会合并

 

延时确认(Delayed Ack);Nagle算法;延时ACK与Nagle算法结合的潜在问题
===========================================================================================
延时确认(Delayed Ack)
一般来说TCP并不对每个到来的数据包都返回ACK,利用TCP的累积ACK字段可以实现该功能。累积确认可以允许TCP延迟一小段时间再发送ACK,从而可以将ACK和同方向上的其他需要传的数据结合发送。当然,TCP延迟的时间不能过长,否则对方会误认为数据丢失而出现不必要的重传。一般TCP实际时延最大取200ms。

采用延时ACK的方法可以减少ACK传输的数目(减少纯ACK包),可以一定程度的减轻网络负载。基于不同的操作系统,延迟发送ACK的最大时延可以动态配置。

Linux使用了动态调节算法,可以在快速ack(TCP_QUICKACK)和延时ACK之间切换。

------------------------------------------------------------------------------------------
Nagle算法
Nagle 算法的基本思想是,当一个TCP连接中有在传数据(即已发送但还未确认的数据),小报文段(<SMSS)就不能发送,直到所有的在传数据都收到ACK。并且在收到ACK后,TCP需要收集这些小数据,将其整合到一个报文段中发送。Nagle 算法强制TCP遵循停等策略,即只有等待收到所有在传数据的ACK后才能继续发送。
Nagle 算法实现了自时钟控制:ACK返回越快,数据传输也越快。在相对高延迟的广域网中,减少了发送报文的数目。

但是在小数据包的情况下,例如上述的ssh应用,使用Nagle算法 没发送一个请求和响应包需要等待一个RTT,这就加长了整个传输过程时延。
Nagle算法的停等行为,在任一给定时刻,只有一个方向保持传输状态,即任一时刻只有一个包在传。


------------------------------------------------------------------------------------------
若将延时ACK与Nagle算法直接结合使用,很可能会影响传输性能。
短暂的死锁:
    0.发送端往接收端发送了一个报文;
    1.接收端在接收到报文后,因为延迟ACK策略,不会立即发送ack,而是处于等待状态,希望有数据一同捎带发送;
    2.发送端由于开启了Nagle算法,必须等待接收到相应的ack;
    3.此时发送端和接收端都处于等待状态
    4.延迟ack计时器超时,等待状态才会被打破
    解决方案:禁用nagle算法
延时确认(Delayed Ack);Nagle算法;延时ACK与Nagle算法结合的潜在问题

 

流量控制与窗口管理

窗口通告;滑动窗口;窗口的滑动
=============================================================================================
窗口通告

窗口通告信息的数值表示发送该窗口信息的通信方,在作为接收方时为即将到来的新数据预留的存储空间。
窗口通告信息实现的是对对端发送流量的限流
    1.当TCP应用程序空闲时,就会排队处理这些数据,致使窗口大小字段保持不变。
    2.当系统处理速度较慢,或者程序忙于执行其他操作,到来的数据返回ACK后,就需要排队等待被处理,这时新数据的可用存储空间就会减小,窗口的大小也即会减小。
    3.若应用程序一直不处理这些排队等待的数据,TCP就必须采用策略限制以至于使发送端停止新数据的发送(若通告窗口为0,没有存储空间)。

每个TCP头部的窗口大小字段表明接收端可用缓存空间的大小,以字节为单位,长度为16位, 但在窗口缩放选项可用大于65535的值。

------------------------------------------------------------------------------------------
滑动窗口
作为全双工传输协议,每个TCP活动连接的两端都维护一个发送窗口结构和接收窗口结构。
TCP以字节为单位维护其窗口结构。 

发送窗口结构:已发送已确认的数据(窗口外)、已发送但未经确认的数据(窗口内)、即将发送的数据(窗口内)、窗口右边界未移动前不能发送的数据(窗口外)
接收窗口结构:已接收并确认的数据(窗口外)、接收后将会保存的数据(窗口内)、不能接收的数据(窗口外)

------------------------------------------------------------------------------------------
窗口的滑动
发送方的发送窗口滑动:
    1.关闭(close),即窗口左边界右移:当已发送的数据得到ACK确认时,窗口左边界右移,窗口变小
    2.打开(open),即窗口右边界右移:对端发来的可用窗口>发送方的窗口,窗口右边界右移
    3.收缩(shrink),窗口右边界右移:【RFC1122】不支持这种做法!
    零窗口:当左右边界相等时,此时发送端不能再发送新数据。这种情况下,TCP发送端会开始探测对方窗口。
接收方的接收窗口滑动(我的总结):
    窗口左边界右移:数据接收并经过应用程序处理后,窗口左边界右移
        不支持SACK的会话:只有到达数据序列号等于左边界时,数据才不会被丢弃
        支持SACK的会话:序列号处于接收窗口范围内的数据都会被接收
    窗口右边界右移:应用程序分配了新的缓存空间时,窗口右边界右移
        不是只有应用程序进行数据处理,窗口右边界才会右移!也有可能设备缓存充足,系统可以不断地分配新的缓存。
窗口通告;滑动窗口;窗口的滑动

 

零窗口和TCP持续计时器
=============================================================================================
零窗口:
    当窗口值变为0时,可以有效阻止发送端继续发送,直到窗口大小恢复为非零值。
    当接收端重新获得可用空间时,会给发送端传输一个窗口更新,通知其可以继续发送数据。
    这样的窗口更新通知一般都为纯ACK包,不能保证其传输的可靠性。

------------------------------------------------------------------------------------------
TCP持续计时器:发送端使用持续计时器间歇性的查询接收端,看其窗口是否已增长。持续计时器会触发窗口探测的传输,强制要求接收端返回包含窗口大小的ACK包。
    【RFC1122】建议在一个RTO之后发送第一个窗口探测,随后以指数时间间隔发送
    窗口探测包含一个字节的数据,采用TCP可靠传输,当TCP持续计时器超时,就会触发窗口探测的发送。与TCP重传计时器类似,该计时器也可以采用指数时间退避来计算持续计时器的超时。
零窗口和TCP持续计时器

 

糊涂窗口综合征;大容量缓存与自动调优;紧急机制
=============================================================================================
糊涂窗口综合征
基于窗口的流量控制机制,有可能会出现交换数据段大小不是全长的而是一些较小的数据段。
这种现象被称为糊涂窗口综合征(Silly Window Syndrome,SWS),由于每个报文段中有用数据相对于头部信息的比例较小,因此耗费的资源也更多,传输效率也越低。

SWS现象可能是由TCP连接的两端导致的:
    接收端通告窗口较小,没有等到窗口变大才通告
    发送端发送的数据段较小,没有等到将其他数据组合成一个更大的报文段。
    
要避免SWS,必须在发送端或接收端实现相关的规则:
    对于接收端,不应通告小的窗口值。在窗口可增至一个全长的报文段(即接收端MSS)或者接收端缓存空间的一半(取两者中较小者)之前,不能通告比当前窗口更大的窗口值。
    对于发送端,不应发送小的报文段,而且需由Nagle算法控制发送,更具体地,为避免SWS问题,只有至少满足以下条件之一时才能传输报文段:
        a)全长(MSS)的报文段可以发送
        b)数据段长度≥接收端通告过的最大窗口值的一半
        c)某一ACK不是目前期盼的(即没有未经确认的在传数据),或该连接禁用Nagle算法
            发送端应用若在执行某些较小的写操作,条件c可以有效避免SWS

------------------------------------------------------------------------------------------
大容量缓存与自动调优
    在相似的环境下,TCP应用的缓存越小,吞吐性能越差,而且受TCP连接两端的影响,即时接收端指定一个足够大的缓存,发送端也可能指定一个很小的缓存,最终导致性能变差。
    因此很多TCP协议栈中上层应用不能指定接收缓存的大小。在多数情况下,上层应用指定的缓存会被忽视,而由操作系统来指定一个较大的固定值或动态变化的计算值。

------------------------------------------------------------------------------------------
紧急机制
TCP头部有一个位字段URG用来指定“紧急数据”。应用要执行写操作时,可通过设置Berkeley套接字API(MSG_OOB)的特殊选项将数据标记为紧急。
当发送端TCP收到这类写操作要求时,会进入紧急模式的特殊状态。 
它记录紧急数据的最后一个字节,用于设置紧急指针字段,随后发送端生成的每个TCP头部都包含该字段,直到应用停止紧急数据写操作,并且所有序列号大于紧急指针的数据都经接收端确认。

    即使接收到通告0窗口,发送端也还是可以发送紧急数据!
    【FRC6093】不再推荐设置紧急数据
糊涂窗口综合征;大容量缓存与自动调优;紧急机制

 =====================================================================================================

《网络排查案例课》10 | 窗口:TCP Window Full会影响传输效率吗? 

Wireshark提示"TCP Window Full"===========================================================================
一般来说,Wireshark 自己分析得到的信息,都会用方括号括起来,而 TCP 报文本身的字段,是不会带这种方括号的。

TCP Window Full : 接收端的接收窗口小于发送端的发送能力而出现的状况。
得出推论:瓶颈在接收端,TCP Window Full 也确实会影响传输速度。
    Bytes_in_flight = latest_nextSeq - latest_ack_from_receiver
    在途数据 = 本报文的nextSeq - 最新的ack 确认的Seq

    当 在途数据 = 接收窗口大小(Calculated window size)时,wireshark将会提示"TCP Window Full"

    ***TCP Window Full 并不是总会出现的***,比如在接收窗口接近满但又不是完全满的时候,哪怕是离窗口满只差 1 个字节,Wireshark 也不会提示 TCP Window Full 了。
        发送端并不会为了这几十KB去单独发送报文,因为这样不效率
        但并不意味着发送端已经....

------------------------------------------------------------------------
速度 = 窗口 / 往返时间  (只有当接收端处理数据极快时,该公式才适用;若数据被放在缓存中,需要等待才会被处理,这时用这个公式就不准确了)(即 接收端有“数据滞留”的现象)
我们可以进一步优化为新的公式:速度 = 确认数据 / 往返时间。
    这个改进后的公式,可以兼容这种有“数据滞留”现象的传输场景。
Wireshark提示"TCP Window Full";
案例:TCP Window Full 是导致异地拷贝速度低的原因吗?
=====================================================================
现象:在对该案例进行抓包分析时,发现几个报文提示了"TCP Window Full"

TCP Window Full是接收端的接收窗口小于发送端的发送能力而出现的状况。
TCP Window Full是结果,而不是原因;当出现TCP Window Full时,传输速度确实会被影响
案例:TCP Window Full 是导致异地拷贝速度低的原因吗?

 

posted @ 2022-04-20 11:25  雲淡風輕333  阅读(96)  评论(0编辑  收藏  举报