TCP 重传、滑动窗口、流量控制、拥塞控制
- TCP 重传
- 超时重传
- 快速重传
- 滑动窗口
- 流量控制
- 拥塞控制
- 慢启动
- 拥塞避免
- 拥塞发生
- 快速恢复
TCP 重传
TCP重传是当发送的报文发生丢失的时候,重新发送丢失报文的一种机制,它是保证TCP协议可靠性的一种机制。
TCP重传有超时重传和快速重传两种机制。
超时重传
超时重传是当报文发送出去的时候,设一个定时器,当定时器到期的时候也没有收到确认应答报文的时候,就重新发送丢失的报文。
比如发送的请求报文丢失:
或者是返回的确认应答报文丢失:
这个定时器的超时时间是有具体公式的,它必须保证超时时长不会太长也不会太短。太短的话可能存在并没有丢包但是却触发重传的情况;太长的话就会等待多余的时间。
快速重传
快速重传则是当连续收到3个相同ack num的报文的时候,就可以确定对端有报文没有接收到,于是未等超时重传的定时器到期,就发送对端缺失的报文。
上面的这个例子,当对端收到了缺失的报文之后,对端返回的ack是4001,代表4000以前的数据都已经接收到,不需要2001、3001等ack都发送一遍,这个叫做累计确认机制。
滑动窗口
TCP的报文头有一个窗口大小的字段,是接收端告诉发送端自己缓冲区还有多少空间可以接收发送端发送的报文。在窗口大小还足够的前提下,发送端不必等待上一个报文接收端返回ack报文,就可以发送下一个TCP请求报文。
比如现在接收端的窗口大小是3000,每个数据包大小都是1000,那么现在发送端就可以连续发送三个数据包而不需要等待接收端的ack。
此时,由于有TCP的累计确认机制,如果中间有某个ack丢失,也不必重发,只要更大的ack被发送方接收到,就能确认前面的数据包都被接收到,发送方无需重发数据包,接收方的ack也不需要重发。
流量控制
有了滑动窗口,接收方就可以通过窗口控制发送方的发送速度,使得发送方不会无脑的发送。
每次接收端返回ack数据包的时候,都会携带当前窗口的可用大小。
当窗口缩小为0的时候,发送方就会停止数据包的发送。然后接收方如果读取了TCP缓存区里的数据,窗口又会腾出空间,此时接收方又可以继续接收数据包。但是此时发送方是不知道的,所以发送方会定时发送探测报文,接收方接收到探测报文时会返回当时的窗口大小。
发送方发送探测报文以后,接收方返回的ack数据包显示窗口又有可用空间了,就会继续发送数据包。当然如果接收方的可用空间太小,发送发还是不会发送的,因为如果只发送几个字节的数据,TCP头部的大小都比数据大的多,那么就非常浪费带宽资源。
拥塞控制
拥塞控制是用于控制发送方发送的速度,避免发生的数据过多导致网络拥塞的。
为了控制发送方的发送速度,定义了一个控制窗口的概念。有了控制窗口,发送发的发送窗口(swnd)就是接收方窗口(rwnd)大小和控制窗口(cwnd)的最小值:swnd = min(rwnd, cwnd)。
拥塞控制主要包括四个算法:慢启动、拥塞避免、拥塞发生、快速恢复。
慢启动
一开始初始化cwnd的大小为1,表示可以传输一个MSS大小的数据。然后每收到一个ack,cwnd就会增加1。
比如一开始发送端发送了一个TCP报文,然后收到接收端返回的ack,此时发送端的cwnd增长为2;然后发送端发送两个TCP报文,当这两个TCP报文的ack都接收到之后,发送方的cwnd就增长为4…如此成倍数增长。
拥塞避免
当cwnd上涨到ssthresh(慢启动门限),就会进入拥塞避免算法。进入拥塞避免算法之后,每收到一个ack,cwnd就增加1/cwnd。
比如按照上图的这个例子,如果ssthresh=8,那么当cwnd上涨到8时,就进入拥塞避免算法,此时每收到一个ack,cwnd就增加1/8,当收到8个ack时,cwnd才变成9,然后后面收到9个ack,cwnd才变成10。
拥塞发生
一旦发生超时重传,就会促发拥塞发生算法,ssthresh变成cwnd/2,cwnd重置为1。
快速恢复
当重复收到3个相同的ack时,就会促发快速恢复算法。快速恢复算法不会像拥塞发生算法那样“一把回到解放前”,因为还能收到3个相同的ack,那表示现在网络状况也不太差,因此不会把cwnd重置为1。
此时会把ssthresh重置为cwnd/2,cwnd重置为新的ssthresh值,然后进入拥塞避免算法。