快速了解TCP的流量控制与拥塞控制
有关TCP你不能不知道的三次握手和四次挥手问题,点我跳转
流量控制
1. 滑动窗口
数据的传送过程中很可能出现接收方来不及接收的情况,这时就需要对发送方进行控制以免数据丢失。利用滑动窗口机制可以很方便地在TCP连接上对发送方的流量进行控制。TCP的窗口单位是字节,不是报文段,发送方的发送窗口不能超过接收方给出的接收窗口的数值。
TCP规定,即使设置为零窗口,也必须接收以下几种报文段:
- 零窗口探测报文段
- 确认报文段
- 携带紧急数据的报文段
确认丢失和确认迟到
持续计时器
存在这样一种情况:发送方接收到零窗口报文之后将发送窗口设置为0,停止发送数据。但等到接收方有足够缓存,发送了非零窗口大小的报文,但是这个报文中途丢失,那么发送方的发送窗口就一直为0导致死锁。
为此,TCP为每一个连接设有一个持续计时器(Persistence Timer):当TCP连接的一方收到对方的零窗口通知时就启动持续计时器。若持续计时器时间到期,就发送一个零窗口探测报文段(携有1字节的数据),那么收到这个报文段的一方就在确认这个探测报文段时给出了现在的窗口值。若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器;若窗口不是零,则死锁的僵局就可以打破了。
2. 延迟ACK
如果TCP对每个数据包都发送一个ACK确认,那么只是一个单独的数据包为了发送一个ACK代价比较高,所以TCP会延迟一段时间,如果这段时间内有数据发送到对端,则捎带发送ACK,如果在延迟ACK定时器触发时候,发现ACK尚未发送,则立即单独发送;
延迟ACK好处:
- 避免糊涂窗口综合症。
- 发送数据的时候将ACK捎带发送,不必单独发送ACK。如果延迟时间内有多个数据段到达,那么允许协议栈发送一个ACK确认多个报文段。减少流量消耗。
糊涂窗口综合症:TCP接收方的缓存已满,而交互式的应用进程一次只从接收缓存中读取1字节(这样就使接收缓存空间仅腾出1字节),然后向发送方发送确认,并把窗口设置为1个字节(但发送的数据报为40字节的的话)。当发送方又发来1个字节的数据(发送方的IP数据报是41字节),接收方发回确认,仍然将窗口设置为1个字节。这样,网络的效率很低。要解决这个问题,可让接收方等待一段时间,使得或者接收缓存已有足够空间容纳一个最长的报文段或者等到接收方缓存已有一半的空闲空间。只要出现这两种情况,接收方就发回确认报文,并向发送方通知当前的窗口大小。此外,发送方也不要发送太小的报文段,而是把数据报积累成足够大的报文段,或达到接收方缓存的空间的一半大小。
拥塞控制
拥塞控制与流量控制的区别 :
拥塞控制是防止过多的数据注入到网络中,可以使网络中的路由器或链路不致过载,是一个全局性的过程。
流量控制是点对点通信量的控制,是一个端到端的问题,主要就是抑制发送端发送数据的速率,以便接收端来得及接收。
拥塞控制的作用
拥塞控制是为了防止过多的数据注入到网络中,这样可以使网络中的路由器或者链路不至于过载。
拥塞控制的算法
我们假定:
- 数据单方向传送,而另外一个方向只传送确认。
- 接收方总是有足够大的缓存空间,因为发送窗口的大小由网络的拥塞程度来决定。
发送方的发送窗口的上限值应当取为接收方窗口rwnd和拥塞窗口cwnd这两个变量中较小的一个,即发送窗口的上限值为Min[rwnd, cwnd]
当rwnd < cwnd时,是接收方的接收能力限制发送窗口的最大值
当cwnd < rwnd时,则是网络的拥塞限制发送窗口的最大值
拥塞控制的过程一共涉及了4种算法:
- 慢启动
- 拥塞避免
- 快重传
- 快恢复
1. 慢启动
发送方维护一个拥塞窗口cwnd的状态变量,拥塞窗口的大小取决于网络的拥塞程度,动态变化。通过逐渐增加cwnd的大小来探测可用的网络容量,防止连接开始时采用不合适的发送量导致网络拥塞。
当主机开始发送数据时,如果通过较大的发送窗口立即将全部数据字节都注入到网络中,由于不清楚网络状况,有可能引起网络拥塞。较好的方法是试探,从小到大逐渐增大发送端拥塞窗口的cwnd数值。
例如:开始发送方先设置cwnd=1,发送第一个报文段M1,接收方接收到M1后,ACK返回给发送端,发送端将cwnd增加到2,接着发送方发送M2,再次接受到ACK后将cwnd增加到4…慢启动算法每经过一个传输轮次,拥塞窗口cwnd就加倍。
当rwnd足够大时,为防止拥塞窗口cwind的增长引起网络拥塞,还需要另外一个变量,慢开始门限ssthresh
当cwnd<ssthresh,使用慢开始算法
当cwnd=ssthresh,既可使用慢开始算法,也可以使用拥塞避免算法
当cwnd>ssthresh,使用拥塞避免算法
首次慢启动的ssthresh值,可以参阅网上的各种讨论,限于篇幅,本文不作介绍~
2.拥塞避免
控制过程:
- TCP连接初始化,将拥塞窗口cwnd设置为1个报文段,即cwnd=1
- 执行慢开始算法,cwnd按指数规律增长,直到cwnd == ssthresh时,开始拥塞避免算法,cwnd按线性规律增长
- 当网络发生阻塞,把ssthresh值更新为拥塞前cwnd的一半(12=24/2),cwnd重新设置为1,再按照(2)执行
让拥塞窗口cwnd缓慢地增大,每经过一个往返时间RTT就把发送方的拥塞窗口cwnd+1,而不是加倍。这样拥塞窗口cwnd线性缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢地多。
无论慢启动开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(没收到ACK),就把慢启动门限ssthresh设置为出现拥塞时的cwnd的一半。然后把拥塞窗口cwnd重新设置为1,执行慢启动算法。这样做的目的是能迅速的减少主机向网络中传输数据,使发生拥塞的路由器能够把队列中堆积的分组处理完毕。拥塞窗口是按照线性的规律增长,比慢启动算法拥塞窗口增长快的多。
拥塞避免是由指数增长拉低到线性增长,降低出现拥塞的可能,并不是能完全避免网络拥塞
3.快重传
一条TCP连接有时会因等待重传计时器的超时而空闲较长的时间,慢开始和拥塞避免无法很好地解决这类问题,因此提出了快重传和快恢复的拥塞控制方法。
为使发送方及早知道有报文没有达到对方,快重传算法首先要求接受方每收到一个报文段后就立即发出重复确认。快重传算法并非取消了重传机制,只是在某些情况下更早地重传丢失的报文段。即,当TCP源端收到3个相同的ACK确认时,即认为有数据包丢失,则源端重传丢失的数据包,而不必等待RTO(Retransmission Timeout)超时。由于发送方尽早重传未被确认的报文段。因此,采用快重传后可以使整个网络吞吐量提高20%
快重传算法要求首先接收方收到一个失序的报文段后就立刻发出重复确认,而不要等待自己发送数据时才进行捎带确认。接收方成功的接受了发送方发送来的M1、M2并且分别给发送了ACK,现在接收方没有收到M3,而接收到了M4,显然接收方不能确认M4,因为M4是失序的报文段。如果根据可靠性传输原理接收方什么都不做,但是按照快速重传算法,在收到M4、M5等报文段的时候,不断重复的向发送方发送M2的ACK,如果接收方一连收到三个重复的ACK,那么发送方不必等待重传计时器到期,由于发送方尽早重传未被确认的报文段。
4.快恢复
快恢复算法控制过程:
当发送方连续收到3个重复确认时,发送方认为网络很可能没有发生拥塞,因此不执行慢启动。而是把cwnd值设为新的门限值,然后执行拥塞避免算法,cwnd值线性增大,避免了当网络拥塞不够严重时采用”慢启动”算法而造成过大地减小发送窗口尺寸的现象,这就是快恢复。
最后,限于笔者经验水平有限,欢迎读者就文中的观点提出宝贵的建议和意见。如果想获得更多的学习资源或者想和更多的是技术爱好者一起交流,可以关注我的公众号『全菜工程师小辉』后台回复关键词领取学习资料、进入前后端技术交流群和程序员副业群。同时也可以加入程序员副业群Q群:735764906 一起交流。