目录
一、流量控制
TCP为它的应用程序提供了流量控制服务来避免发送方因为发生速率过快导致接收方缓存溢出数据丢失的问题
说白了流量控制就是让发送方的发送速率不要太快,让接收方来得及接收。
二、拥塞控制
简单理解就是由于ip网络自身拥塞导致发送方发送能力被遏制住了。在这样的情况下,网络已经很堵了,那发送方发送速率需要被控制,这种控制就叫拥塞控制。
流量控制和拥塞控制都是对发送方进行控制的。
前者是解决发送和接收速率不匹配问题的。
后者由于网络本身拥堵,发送方不得不采取速率控制来避免网络更加拥堵。
滑动窗口进行流量控制。
主机A(发送方)给接收方B发送数据的时候要维护一个窗口,称之为接收窗口。接收窗口的作用就是告诉发送方 接收方还有多少可用的缓存空间,TCP呢是全双工通信,那接收方也可以是发送方,所以说通信的任何一方都维护着另一方的一个接收窗口。
接收窗口:它的值表示接收方当前可用的缓存空间。
例如:主机A通过一条TCP连接向主机B发送一个大文件,那主机B呢得为这个链接去分配一个接收缓存,那这个缓存大小呢,用receive buffer来表示。那发送方发送的数据呢首先会进入缓存空间。接收方就从这个缓存中去读取数据,红色区域表示它写入的数据,绿色区域表示已经被读过了或者说为被使用的空间。这个时候呢应用程序不停的去消费这些数据,那发送方呢就不停的写数据,就一定会存在两个位置,一个是lastByteRcvd;一个是lastByteRead。第一个表示从网络中到达当前缓存的数据流的最后一个字节的编号。后者是应用程序最后一次缓存中读的位置。
所以有
lastByteRcvd - lastByteRead <= RevBuffer
Rwnd = RevBuff - (lastByteRcvd - lastByteRead)
Rwnd就是剩下的绿色部分,绿色部分就表示我们的接收窗口。接收窗口就是表示接收方还能有多大的缓存空间,那这个大小肯定也是动态变化的,也就是说接收窗口的大小也是动态变化的,所以我们会把这个窗口称之为滑动窗口。
那这个时候又有一个问题了,接收方的滑动窗口是动态变化的,那发送方是怎么拿到接收方的这个窗口大小数据的?
其实很简单,TCP是全双工通信,这个时候接收方可以再发送一个报文告诉发送方,发送方就知道了接收方的接收窗口是多大了,这个值放在TCP报头中的一个窗口大小里。
发送方也需要维持两个变量,lastByteSent;lastByteAcked,前者是最后一次发送的比特位置,后者是最近一次收到的确认包的比特位置
发送方只需要去控制这两个的差小于等于接收窗口大小就可以了。
TCP拥塞控制
出现拥塞的原因
通过上面的流量控制,解决了发送方和接收方发送速率和接收速率不匹配的问题。在理想情况下,只要在不超过接收窗口大小情况下,发送方尽可能快的去发送数据,但是现实是所有的数据包都是跑在IP网络上的,这个网络是构建在大量的路由器、交换机、光纤的通信设备上的,以路由器为例,它就是将分组数据包从一台发送主机移动到另一台接收主机上,这期间会涉及到两个主要操作,路由选择和转发,每个路由器内部都有一个转发表,路由器通过检查到达的数据包通过在转发表中进行索引来实现转发,路由器在接收分组信息的时候,是需要做缓存的。缓存的容量是有限的,如果每个发送方都以过快的速率去发送数据包,就有可能导致缓存溢出丢失了大量数据包。当然TCP作为可靠传输协议有自己的重传机制。丢包超时就是网络拥塞的主要特征。同样的,作为网络传输介质,光缆也有传输容量上限。超出容量上限的话,数据包发送的话就需要排队,就加大了通信的时延。
TCP如何进行拥塞控制
每个TCP连接的发送方都会自己去感知网络的拥塞程度,然后进行拥塞控制。只要发生丢包事件,具体说的话就是出现超时,出现这个现象就知道了当前网络拥塞了 。
TCP的每一端除了维护进行流量控制的滑动窗口外,还要维护一个拥塞窗口CWND,拥塞窗口就是对TCP发送方的发送速率进行限制的。
lastByteSent - lastByteAcked <= Math.min(cwnd,rwnd)。rwnd滑动窗口,cwnd拥塞窗口。
TCP会控制发送方发送到连接中但是还没有被接收方确认的数据量。通过改变cwnd的值就可以改变发送窗口的大小,这样就能调整发送的速率。
cwnd/rtt = 速率(字节/秒) //一般rtt比较固定。
接下来就要确认发送的速率为多少才算合适。由TCP的拥塞控制算法来进行确认了。
拥塞控制算法
慢开始、拥塞避免、快重传、快恢复
拥塞控制算法就是来调整拥塞窗口大小的。
这里的大小,单位是mss(最大的传输单元)。tcp分为tcp首部和数据两部分。mss就是控制数据字段的大小的,这个值是需要通讯双方进行约定,一般的话是一千四百六十个字节。
控制过程:刚开始的时候因为不知道网络是否拥塞,于是就从小到大逐渐增大窗口的值,如果说当前窗口发送的报文全都收到了确认报文,那这个时候就直接将窗口大小乘2,指数增长。这个过程就是慢开始,为了避免cwnd的值增长过快,就需要做一个限制,在慢开始阶段引入一个阈值,一旦当前窗口大小大于这个ssthresh(阈值),就要采用拥塞避免算法了;拥塞避免算法也是让cwnd窗口增大的,但是没有慢开始阶段那么快,是呈线性增长的,一直增长到网络拥塞的一个状态,也就是超时了,一旦发生超时,发送方就认为发生了网络拥塞,这个时候就把慢开始的阈值减为当前窗口大小的一半,窗口大小变成1,然后又开始慢开始增长窗口大小直到到达阈值,到达阈值就采用拥塞避免算法。
但是有时候在传输的过程中出现了丢包情况,tcp就引入了第三种算法,快重传,就是让发送方尽可能去知道个别报文段丢失了需要重传。这个过程就是接收方接收到了有序报文数据后就立刻去发送确认报文。接收到12的时候,需要接受3,不去确认456,而是重复确认m。重复确认3次就会触发快重传。快重传避免了一直等待确认而超时的情况。当发送方需要进行快重传的时候,也需要降低慢开始的阈值(ssthresh),但是不需要从头开始了,直接从阈值开始进行拥塞避免算法来增大窗口,省去了一个慢开始阶段。那快速到达阈值的这个阶段就称为快恢复