滑动窗口
大家都口口相传TCP是安全的可靠的网络传输协议。
要做到可靠要解决很多问题,其中一个问题就是:发送方能力和接收方能力不一样怎么处理? 这次要讨论的TCP滑动窗口的技术就是解决了这样一个问题的,保证了发送方能和接收方保证相同的大小。
那为什么要解决这样一个问题呢?因为如果发送方发送速度太快,会出现接收方数据overflow,这就会浪费流量导致网络拥塞等。
TCP是如何保证数据包的次序?
TCP是如何保证数据的有序性的呢?
答:发送方发送一个包1,这时候等待确认包1。确认包1以后才发送包2,确认包2。以此下去,直到发送完所有的数据包。问题:吞吐量非常低。
如何提高吞吐量呢?
我们同时发送几个包过去一起确认,这样速度会不会更快呢?
答: 2个包一起发送过去,一起回来,所以总共耗时一个来回RT,原本需要2个来回的时间现在只需要一个来回。速度肯定有提升的。
如何平衡吞吐量呢
确定一次发送多个数据包过去会提示整体速度,那么一次发送多少合适?
为了确定的准备的数据包数量,出现了滑动窗口。
图1:
图2:
窗口滑动的过程:
图1中1-3号的数据包已经完成了发送并且接收到了ACK,标记为灰色。4-7为发送了但是没有收到ACK,标记为黄色,绿色的部分是待发送的,而白色的部分是不在窗口内部等待发送到的数据包。
图2中,当4号数据包收到了ack以后,窗口向右移动一格,4号数据包变成已发送状态,把11号数据包读进缓存。
这是发送方角度的窗口移动,并且他的大小是变动的,取决于接受方返回的rwnd (receiver window)大小。也就是说,每次发送方接收到ack的同时,会接受一个rwnd大小,来实时改变滑动窗口大小。这样就可以保证发送方和接受方能力大致匹配。
上面是理想情况,但是数据包在网络上传输时,往往情况复杂。
介绍下TCP 在处理错误或者优化时的几种方式:
重传机制:超时重传,快速重传,SACK,D-SACK
超时重传:
RTT(Round-Trip Time 往返时延):表示数据从网络一端传到另外一端的往返时间。
RTO(Retransmission Timeout): 发送端长时间没有得到应答重新发起请求的时间--- 超时重传
RTO 应该略大于RTT
超时重传是以时间为驱动的,时间应该略大于往返时间
快速重传:
快速重传则是以数据为驱动的
发送包以后一般会收到ack确认包,当连续没有收到某一个确认包的时候,会触发重传机制。
SACK方法
会在TCP的头部字段里面加一个SACK的字段,该字段会缓存接受到哪些发送方的数据包,这样就可以知道哪些数据没有收到,可以重传丢失的数据
具体的可以参考:你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了 - 掘金
拥塞窗口机制:慢启动、快速恢复、拥塞避免
慢启动:
所谓慢启动就是在TCP刚建立连接的时候,一点一点提高提高发送数据包的数量。如果一上来就传大量的数据包,这是不准确的。
慢启动的算法:当发送方每收到一个ACK,就拥有窗口的大小就会加1,2会变4,4会变8,8会变16成指数增长。
那么慢启动会一直增下去吗?
肯定不是,会有一个叫慢启动门限的状态变量 ssthresh
当 cwnd < ssthresh时,会使用 【慢启用】 算法。
当 cwnd >= ssthresh时,就会使用【拥塞避免算法】
拥塞避免算法
拥塞避免:顾名思义就是避免拥塞,就是要降低发送数据包的数量。从之前的指数增长变成了线性增长。怎么叫线性增长呢?之前慢启动是1个ACK都会增加让cwnd增加一个,就像细胞分裂一般。一变二,而变4。现在拥塞避免纬度就是轮次。当完成一个轮次cwnd增加一个。也就是线性的增长了。
拥塞发生
当发生了 【超时重传】,则就会使用拥塞发生算法。
该算法可以简单理解,回到了刚建立TCP连接时候的慢启动。
ssthresh设置为了 cwnd / 2,并且cwnd 大小重制为了 1.
快速恢复
快速恢复可以和拥塞发生相比,没有一夜回到解放前,而是比较缓和的下降然后缓和的上升。
cwnd = cwnd/2
,也就是设置为原来的一半;ssthresh = cwnd
;
参考: