TCP协议探究(三):RTT、滑动窗口和阻塞处理
1 RTT算法
1.1 概述
上一节说了重传机制需要设置一个重传超时值(RTO,Retransmission TimeOut),RTO设长了,重发太慢;设短了,可能导致包没有丢,就重发了,可能导致雪崩效应(重发多,失败多,失败多,导致更多的重发...请参考: 暴风门事件)。
那么该值怎么设置?
- 由于一开始无法确定设置某个值,所以需要程序自动适应,动态地去设置
- RTT,Round Trip Time,设置的参考值为数据报来回所需要的时间
1.2 经典算法
采样最近几次的RTT
SRTT计算(Smoothed RTT):α (加权移动平均)取值在0.8 到 0.9之间
$$
SRTT = ( α * SRTT ) + ((1- α) * RTT)
$$计算RTO:UBOUND为最大RTT(上限值),LBOUND为最小RTT(下限值),β 值一般在1.3到2.0之间
$$
RTO = min [ UBOUND, max [ LBOUND, (β * SRTT) ] ]
$$
1.3 Karn / Partridge 算法(SRTT算法的优化)
- 经典算法的问题:
- 原始 + 重传 + ACK = 总时间作为RTO,算长了(特殊情况)
- 重传 + ACK = 总时间作为RTO,算短了(特殊情况)

- 该算法的最大特点:忽略重传,不把重传作为采样
1.4 Jacobson / Karels 算法
忽略重传的问题:
- 在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重传所有的包(RTO设置的比较小)
- 但是由于重传不会重新更新RTO,导致一直丢包,一直重试了。
SRTT算法以及优化都逃不出RTT有一个大的波动的话,很难被发现,所以需要综合考虑。
公式:
SRTT = SRTT + α (RTT – SRTT) —— 计算平滑RTT
DevRTT = (1-β)DevRTT + β(|RTT-SRTT|) ——计算平滑RTT和真实的差距(加权移动平均)
RTO= µ * SRTT + ∂ *DevRTT —— 神一样的公式
# 在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 —— nobody knows why, it just work.
2 滑动窗口
2.1 概述
- 第一节说过TCP可靠性的保证之一就是流量控制(Flow Control)。
- TCP需要知道现在网络的数据处理速度,才能更好防止丢包,而流量控制就是为了测量现在的网络数据处理速度的。
- TCP报头有一个字段:窗口,该字段是接收端告知发送端自己的缓冲空间,防止发送端发送太快缓冲区溢出。
2.2 缓冲空间

- 其实类似java的NIO中的ByteBuffer
- 发送端:
- LastByteWritten:上层应用可写入的位置
- LastByteSent:正在发送的位置
- LastByteAcked:已经收到ACK的位置
- LastByteAcked ~ LastByteSent区间:表示已经发送但是未收到ACK的数据
- LastByteSent ~ LastByteWritten区间:表示未发送出去的数据
- 接收端:
- LastByteRead:TCP缓冲区中读到的位置
- NextByteExpected:收到的连续包的最后一个位置
- LastByteRcved:收到的包的最后一个位置
- NextByteExpected ~ LastByteRcved区间:未到达的数据区间
- LastByteRead ~ NextByteExpected区间:已收到的数据区间
- 接收端回复:
- ACK中会汇报自己的Window = MaxRcvBuffer – LastByteRcvd – 1(只剩下这么多的空间能装新的数据)
- 发送方会根据窗口来控制发送数据的大小,以保证接收方可以处理
2.3 滑动窗口
(1)发送方滑动窗口示意图:

- #1 已收到ACK确认的数据
- #2 已发送到未收到ACK确认的数据
- #3 在窗口中未发出的(接收方还有空间)
- #4 窗口以外的数据(接收方没有空间)
- 其中#2 + #3的黑框就是滑动窗口
(2)发送方滑动后的滑动窗口示意图:

- 红色是已经新收到ACK的数据
- 绿色是新加入滑动窗口的数据
(3)接收端控制发送端的图示:

(4)Zero Window(坚持定时器实现):
- 上图一个处理缓慢的Server将Client的TCP 滑动窗口给降到0.
- 降到0之后,发送端发送Zero Window Probe包(ZWP)给接收方,让接收方ACK它的Window尺寸,一般发送3次,每次30~60秒。
- 连续3次为0,有些TCP Client将发送RST把连接断开。
(5)Silly Window Syndrome(糊涂窗口综合症)
由于处理缓慢的Server把TCP接收方的滑动窗口不断降低,导致滑动窗口很少(如:4个字节),此时发送端仍然义无反顾的发送。
MSS默认为536,有效数据才4个字节,带宽利用率1%不到,造成了巨大的浪费。
窗口是为了控制传输过程中的速度。而MSS是为了控制TCP报文段大小。
MTU = MSS + TCP头(20字节) +IP头(20字节)。
解决方案:
- 问题由Receiver引起,那么Receiver收到的数据导致window size(rwnd,receiver window)小于某个值,可以直接ack window size为0给Sender,这样就把window关闭了,也阻止Sender再发数据过来,等到Receiver处理了一些数据后window size大于等于MSS时,或者Receiver Buffer有一般为空(具体策略有很多),可以把window 打开让Sender发送数据过来。
- 问题由Sender引起,使用延时处理,禁止大量小包发送。(打开之后无法使用telnet或者SSH这种交互性比较强的程序)
- 等到Window Size >= MSS 或者 Data Size >= MSS
- 收到之前发送数据的ACK包,它才会发送数据,否者继续积攒数据
3 阻塞处理
3.1 概述
- 前面说过网络波动时,TCP报文超时,引起重传,但是重传导致网络负担更大,可能导致网络更加繁忙。
- 所以TCP不会这么自私,它在发现阻塞时,会主动让路(并不是直接停止发送TCP报文)。
- 阻塞控制算法:
- 慢启动
- 阻塞避免
- 阻塞发生时快速重传(上一节说过)
- 快速恢复
3.2 慢启动算法
- 程序刚刚加入网络时,一点一点提升速度。
- 算法流程:
- 连接建好的开始先初始化cwnd = 1(窗口),表明可以传一个MSS大小的数据
- 每当收到一个ACK,cwnd++,线性上升
- 每当过了一个RTT,cwnd = cwnd*2, 呈指数上升。
- ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”

3.3 阻塞避免算法
- 一般来说ssthresh的值是65535,单位是字节,当cwnd达到这个值时后
- 算法流程:
- 收到一个ACK时,cwnd = cwnd + 1/cwnd
- 每过一个RTT时,cwnd = cwnd + 1

3.4 阻塞状态时的算法
当丢包的时候,有两种情况
等到RTO超时,重传数据包,TCP认为该情况太糟糕了
- sshthreash = swnd / 2
- cwnd 重置为1
- 进入慢启动算法
快速重传算法,即收到3个重复的ACK就开始重传,无需等待RTO超时
- TCP Tahoe(代表版本)的实现和RTO超时一样。
- TCP Reno的实现:
- cwnd = cwnd / 2
- sshthresh = cwnd
- 进入快速恢复算法——Fast Recovery
3.5 快速恢复算法(TCP Reno)
这里就讲解TCP Reno版本的快速恢复算法,想了解更多请参考:TCP 的那些事儿(下)
算法流程:
- cwnd = sshthresh + 3 * MSS(3的意思是确认有3个数据包被收到了)
- 重传Duplicated ACKs指定的数据包
- 如果再收到 Duplicated ACKs,那么cwnd = cwnd +1
- 如果收到了新的Ack,那么,cwnd = sshthresh ,然后就进入了拥塞避免的算法了。
缺点:由于3个重复的ACKs,并不代表只丢了一个数据包;如果丢了多个数据包,将导致RTO。

参考:https://coolshell.cn/articles/11609.html
TCP协议探究(三):RTT、滑动窗口和阻塞处理的更多相关文章
- TCP协议中三次握手
TCP/IP是互联网相关的各类协议族的总称 TCP/IP协议族分为:应用层,传输层,网络层,数据链路层 应用层:向用户提供应用服务时的通讯的活动 传输层:提供处于网络连接中的两台计算机之间的数据传输 ...
- python摸爬滚打之----tcp协议的三次握手四次挥手
TCP协议的三次握手, 四次挥手 三次握手过程 1, 服务器时刻准备接受客户端进程的连接请求, 此时服务器就进入了LISTEN(监听)状态; 2, 客户端进程然后向服务器发出连接请求报文, 之后客户端 ...
- TCP协议的三次握手和四次分手
HTTP连接 HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用. ...
- 通俗大白话来理解TCP协议的三次握手和四次断开
from : https://blog.csdn.net/Neo233/article/details/72866230?locationNum=15&fps=1%20HTTP%E6%8F%A ...
- 通俗大白话来理解TCP协议的三次握手和四次分手
通俗理解: 但是为什么一定要进行三次握手来保证连接是双工的呢,一次不行么?两次不行么?我们举一个现实生活中两个人进行语言沟通的例子来模拟三次握手. 引用网上的一些通俗易懂的例子,虽然不太正确,后面会指 ...
- TCP协议探究(四):定时器
1 概述 重传定时器:使用于当希望收到另一端的确认. 坚持(persist)定时器:使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口 保活(keepalive)定时器:用于检测一个空闲连接的另一 ...
- TCP协议的三次握手和四次挥手过程
TCP是一种面向连接(连接导向)的.可靠的基于字节流的传输层通信协议.TCP将用户数据打包成报文段,它发送后启动一个定时器,另一端收到的数据进行确认.对失序的数据重新排序.丢弃重复数据. 1.TCP/ ...
- TCP协议探究(一):报文格式与连接建立终止
一 TCP:传输控制协议报文格式 1 TCP服务 提供面向连接.可靠的字节流服务 面向连接意味着两方通信,不支持多播和广播 可靠性的支持: 应用数据被分割成TCP认为最适合发送的数据块.由TCP传递给 ...
- 计算机网络之流量控制(停止-等待协议、滑动窗口、后退N帧协议GBN、选择重传协议SR)、滑动窗口、可靠传输机制
文章转自:https://blog.csdn.net/weixin_43914604/article/details/104908762 学习课程:<2019王道考研计算机网络> 学习目的 ...
随机推荐
- Leetcode题目322.零钱兑换(动态规划-中等)
题目描述: 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: 输入: c ...
- HearthBuddy 召唤随从的问题
代码如下,在SilverFish\SilverFish\ai\Playfield.cs文件中 public void callKid(CardDB.Card c, int zonepos, bool ...
- Python 自学笔记(五)
1.布尔值 1-1.概念 定义计算机中的逻辑判断,只有两种结果,True和False. if,while后面的判断条件就是布尔值,只有条件为True的时候才执行. 1-2.数值比较 1-3.数值运算 ...
- c++ Container print
template<typename Container>void PrintContents(const Container& con) { Container::const_it ...
- 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_21-CMS前端页面查询开发-Api调用
在api里面定义js方法获取服务端的数据 把home模块的下的home.js文件复制到api的目录下改名叫做cms.js 复制过来 默认的代码 实际上引用的是base下的api/public.js文件 ...
- Java NIO学习笔记四 NIO选择器
Java NIO选择器 A Selector是一个Java NIO组件,可以检查一个或多个NIO通道,并确定哪些通道已准备就绪,例如读取或写入.这样一个线程可以管理多个通道,从而管理多个网络连接. 为 ...
- SpringBoot: 14.异常处理方式4(使用SimpleMappingExceptionResolver处理异常)(转)
修改异常处理方法3中的全局异常处理Controller即可 package bjsxt.exception; import org.springframework.context.annotation ...
- EasyUI datagrid列隐藏与显示
隐藏DataGrid某一列 $("#datagrid_view").datagrid('hideColumn', filed); 2. 显示DataGrid隐藏的某一列 $(&qu ...
- Hadoop 部署之 Hadoop (三)
目录 一.Hadoop 介绍 1.HDFS 介绍 2.HDFS 组成 3.MapReduce 介绍 4.MapReduce 架构 JobTracker TaskTracker 二.Hadoop的安装 ...
- <marquee>滚动文字</marquee>
<marquee>滚动文字</marquee> 水平滚动: <marquee direction=">水平滚动字幕内容</marquee> 垂 ...