一,滑动窗口
窗口:发送者发送的连续字节序列的集合
滑动:发送的窗口可以随发送过程而变化。
为什么需要窗口:不必每一个段进行一次确认应答,而是以一个窗口的大小进行确认。减少往返时间,提高速度。(TCP在发送时其实是以字节为单位的)
窗口控制和重发机制:
1,数据已到达对端,但确认ack丢失,这种情况是不需要重发的。如果没有使用窗口机制则需要重发。某一个ack丢失,在窗口机制下可以通过下一个确认ack进行应答。在滑动窗口下,就算某些应答丢失也不会重发。
2,某个报文段丢失,一直重发发送确认ack。但对端该发送的还在发送。如果发送方连续收到3次同一个确认ack,就会重发数据。但是此时数据已经乱序了。这就是快速重发。
滑动窗口的功能:
1,保证数据的可靠传递
- 未确认的数据必须被发送方缓存起来
- 确认的数据将会移除缓冲区
2,保证数据的有序传输
- 乱序的数据必须被接收方缓存起来
3,提供End-to-End的流控机制
- 发送方发送太快就必须阻塞等待
什么是流量控制:
所谓流量控制,主要是接收方传递信息给发送方,使其不要发送数据太快,是一种端到端的控制。主要的方式就是返回的ACK中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送
流量控制的两个极端:
- 一次发送一个字节(停等协议,效率极低)
- 发送拥有的所有数据(可能使接收方来不及接收,原端也无法尽快知道数据包的丢失)
TCP使用折中的方式:滑动窗口协议,发送方和接收方都有滑动窗口。
发送方滑动窗口:
窗口移动:
1,关闭,即窗口左边界右移。当已发送数据得到ack时,窗口会减小。
2,打开,右边界右移,使得可发送数据量增大。当确认数据得到处理,接收端可用缓冲区变大,窗口也随着变大。
3,收缩,窗口右边界右移,不允许这种做法。
一个字节探测包和0通告窗口:
- 接收方发送了一个通告窗口为0的ACK,这种情况下发送方必须暂停发送数据,直到一个新的带非零窗口的通告(ACK)收到为止。
- 为了避免非零窗口的通告丢失,发送方在收到零窗口后启用persistence timer,发送1个字节的探测数据包,直到窗口重新打开为止。
注意:
- 实际发送窗口大小是rwnd(接收端TCP报文的窗口大小字段)和cwnd(拥塞窗口大小)中的较小值。
- 源端并非必须要发送整个窗口大小的数据。
接收方滑动窗口:
第一部分,是已接收到了并确认的,但是还没被进程消耗。此时还需要占用接收缓冲区
第二部分,是接收窗口,接收后将会保存。
第三部分,不能接收。
二,拥塞窗口
拥塞:路由器因无法处理高速到达的流量而被迫丢弃数据信息的现象称为拥塞。
为什么有的流量控制,还需要拥塞控制?
- 流控只简单地表明了接收方的处理能力,并不能代表中间网络的处理能力
- 如果一开始把流控窗口内的数据全部发送出去,中间路由器可能一时处理不了如此多的突发流量
拥塞窗口(cwnd)和通告窗口(awnd)
实际的发送窗口:W=min(cwnd,awnd)。两者之间较小的。
如果接收方慢:W=awnd
如果网络慢:W=cwnd
拥塞控制算法:
- 慢启动
- 拥塞避免
- 超时重传
- 快速重发
- 快速恢复
慢启动:
- 初始化:cwnd=1mss;
- 以后每收到一个ack,cwnd+=1mss;
- 相当于指数增大
拥塞避免:
- 当cwnd超过ssthresh(慢启动阈值)时,每收到一个ack,cwnd+=1/cwnd;
- 相当于加法增大
超时重传:
- cwnd越来越大,导致有包丢失。这时需要重传数据。
- ssthresh=max(cwnd/2, 2) 这个的意思是cwnd/2 但是至少是2个报文段
- cwnd=1,重新进入慢启动
下图为以上描述的整个过程
快速重传:
- 发送方收到3次重复的ack,就立即重传数据。
- ssthresh=max(cwnd/2, 2);
快速恢复:
- cwnd=ssthresh+3MSS;
- 每收到重复的ack,cwnd+=1MSS;
当收到新的ack时,cwnd重设为ssthresh,并退出快速恢复阶段。cwnd=ssthresh,然后进入加法增大(拥塞避免)