本文共 3574 字,大约阅读时间需要 11 分钟。
我们知道,TCP是通过AIMD算法来控制发送速度的.UDT使用类似的算法来调整数据包的发送周期
UDT发送周期,即每个数据包之间的间隔时间,初始值为0.
UDT每隔10毫秒都会调整它的发送速度,当收到ACK消息时,会提升发送速度,而当收到NAK(UDT数据包ACK的一种格式,表示不会对某个数据包进行ACK)时则减少发送速度. 另一种情况则是发生了超时,此时按情况调整,可以不减少。UDT的滑动窗口,表示正在传输中的数据包,其初始大小为2,会根据ACK返回的信息更新其窗口大小值,需要注意的是要避免大小为0的情况出现(永远发送不出数据包,也不会收到ACK),CWND可以跟接收方的缓存大小保持一致。
UDT调整发送速率的固定周期,一般为10ms。
UDT拥塞控制包含两个阶段,慢启动阶段和常规发送阶段,每个连接建立之初处于慢启动阶段,当发生丢包或者滑动窗口CWND已满时,进入常规发送阶段.并且UDT中所有的数据包应当具有相同的大小。发送方会连续发送两个相同大小的数据包,接收方接收到时,会根据包间隔来计算出链路带宽。
在发送端,UDT每发送16个数据包就会发送一次对包,即第16,17号数据包成为一个对包,由于在只有16号数据包,没有17号数据包时(或17号包很晚才发),接收方计算间隔时间会出现非常大的值,此时链路带宽会出现比较大的波动,所以UDT采用中值过滤法来避免这种情况。一个大小为N的循环链表,接收方维护了最近N个对包的对包间隔窗口,N可以是任意数值,越大需要的内存和CPU消耗越高,在UDT中N=64,每次都会使用最新的间隔时间来替换掉最老的间隔时间,接收方使用中值过滤法来去除噪音,UDT计算出对包窗口中的中值,所有大于中值8倍,或者小于中值1/8的数据都会被忽略掉,然后再计算余下有效的间隔时间的平均值,带宽就通过平均值来计算出来
B = 包大小 / 平均间隔时间
对包窗口内的间隔时间,全部初始化设置为1秒(安全,考虑低带宽的情况),接收方对链路大小进行评估后,将评估值b通过ACK返回给发送方。
发送方接收到新的评估值b后,使用如下公式更新已有带宽值B(能处理10到1/10倍的错误数据):B = B * 0.875 + b * 0.125
往返时延,UDT采用一种叫做ACK子序列的方式来计算RTT,接收方记录下发送的ACK时间和序号,然后等发送方返回ACK2(ACK的ACK)时,根据ACK2中携带的ACK序号,计算ACK2的到达时间和ACK的发送时间,即可得出RTT.计算公式如下,RTT表示已有值,rtt表示新计算出来的值
RTT = RTT * 0.875 + rtt * 0.125RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125
RTT通过ACK返回给发送方,RTTVar保存在本地,发送方收到新的RTT值时也通过上述公式更新其RTT值,RTTVar表示RTT的差值,用于计算RTO。
重传超时,UDT中最小值为100ms
RTO = RTT + 4 * RTTVar
接收方记录了最近N个数据包之间的间隔(我们叫它接收时间窗口,大小为N),跟对包技术不同的是,对包只记录第16,17个数据包之间的时间间隔,包接收速率AS计算公式如下
AS = 1 / 平均间隔时间
在计算平均间隔时间时同样需要采用中值过滤法来过滤噪声,去除大于中值8倍和小于中值1/8的数据,然后计算平均值。
负责修改AS,SND,和CWND.
之前说到,拥塞控制算法有两个阶段,慢启动和常规阶段.在慢启动阶段中,SND初始化为0,CWND初始化为2,当每次ACK到达时设置为已经发送出的数据包总数,当收到NAK包,或者已发送的数据包总量达到CWND最大值时退出慢启动阶段。在慢启动的末期,SND包发送间隔设置为 1 / 包接收速率SND = 1 / AS
之后进入常规阶段,常规阶段会调整通过调整 inc 这个参数来调整SND,增量 inc 通过下面公式算出
if (B <= C) inc = 1/MSS;else inc = max(10^(ceil(log10((B-C)*MSS*8))) * Beta/MSS, 1/MSS);
B:链路带宽,C:当前发送速率,即C = 1 / SND = AS,MSS:MSS = MTU - UDP/UDT头大小,通常为1400,Beta:常量 0.0000015
B和C的单位都是 包数量 / 每秒,如果是以 字节 / 每秒为单位,那么可以去除MSS,算出增量 inc 后,SND和CWND通过下面公式更新:SND = ( SND * SYN ) / ( SND * INC + SYN )CWND = AS * (RTT + SYN ) + 16
在常规阶段,每个SYN周期内,SND只能被更新1次。
在此我们要知道一个拥塞周期的概念,拥塞周期就是在收到的NAK中数据包序号比已发出的最大数据包序号LastDecSeq还要大时开始,持续到下一个拥塞周期开始时结束。举例:
LastDecSeq=0 NAK NAK LastDecSeq=100 NAK |----------------60---------80---------------100------------140------->
在一开始时 LastDecSeq = 0, 当收到NAK(60)时,判断有NAK发生,进入拥塞周期,将LastDecSeq=100,然后进行降速处理
在收到NAK(80)时,查看LastDecSeq ,发现LastDecSeq比当前NAK序号大,说明还在同一个拥塞周期内,NAK(60)已经进行过降速处理,此时仍降速,幅度调小 发送方持续发送数据包,当收到NAK(140)时,发现NAK序号比LastDecSeq大,进入下一个拥塞周期,进行降速处理,幅度恢复正常降速算法中用到4个参数,参数名以及他们的初始值分别如下:
AvgNAKNum = 1 : 拥塞周期内收到的NAK数量的平均值 NAKCount = 1 :当前拥塞周期内收到的NAK数量 DecCount = 0 :发送速率在当前拥塞周期内已经被降速的次数 LastDecSeq = 初始化序列号-1
If this NAK starts a new congestion period{increase SND = SND * 1.125;Update AvgNAKNum;Reset NAKCount to 1;Compute DecRandom to a random (uniform distribution) number between 1 and AvgNAKNum;Reset DecCount to 1;Reset Update LastDecSeq;Stop.}If (DecCount <= 5) and (NAKCount == DecCount * DecRandom){Update SND period: SND = SND * 1.125;Increase DecCount by 1;}Update LastDecSeq and NAKCount.
DecRandom是一个位于1 和 周期内平均NAK数量 AvgNAKNum 之间的随机数,比如DecRandom=2,UDT就会在第1,2,4,6个NAK时进行降速,每次降速1 / 8, 但是因为每个周期内发送速率降速不能超过1 / 2 ,否则就变成AIMD了,所以在收到第6个NAK时就开始不进行降速了。
RTO是一个定时器,只会被ACK和NAK重置,RTO事件会触发重传和降速,当RTO次数超过一定阈值时,就可以认为链接已经断开了。.
GIT :[ ()
转载地址:http://lszeo.baihongyu.com/