UDT协议拥塞控制机制总结

UDT协议拥塞控制机制总结

重要名词:

SYN:DT increases its sending rate every 10 milliseconds, this constant time is defined as SYN

SND:据包发送时间间隔,决定了数据包发送速率。

UDT允许用户访问两个拥塞控制参数:拥塞窗口大小和包与包之间的发送间隔。用户可以调整这两个参数来实现基于窗口的控制算法、基于速率的控制算法或者是一套混合的控制算法。

拥塞算法控制的核心变量:"拥塞窗口大小cwnd"和"包与包之间的发送间隔SND"。

控制时机:onACK,onLOSS,onTImeout,发生这些事件时更改上述2个变量。

分析思路:通过控制时机改变“拥塞窗口大小cwnd"和"包与包之间的发送间隔SND"这2个值,发包时通过这2个值决定发包行为。

拥塞过程:拥塞过程分为Slow start phase和regular phase阶段。 Slow start phase存在且仅存在于the beginning of a connection时。在slow start pha阶段, 数据包发送时间间隔 (SND) 为0. 拥塞窗口cwnd为2 ,且每次ACK到来时被设为the number of total sent packets so far。当收到NAK包或者达到最大cwnd窗口时 slow start阶段停止,SND = 1/ AS(arrival speed),进入regular阶段。

 

On ACK packet received:
   1) If the current status is in the slow start phase, set the
      congestion window size to the product of packet arrival rate and
      (RTT + SYN). Slow Start ends. Stop.
   2) Set the congestion window size (CWND) to: CWND = A * (RTT + SYN) +
      16.
   3) The number of sent packets to be increased in the next SYN period
      (inc) is calculated as:
         if (B <= C)
            inc = 1/PS;
         else
            inc = max(10^(ceil(log10((B-C)*PS*8))) * Beta/PS, 1/PS);
      where B is the estimated link capacity and C is the current
      sending speed. All are counted as packets per second. PS is the
      fixed size of UDT packet counted in bytes. Beta is a constant
      value of 0.0000015.
   4) The SND period is updated as:
         SND = (SND * SYN) / (SND * inc + SYN).
 

On NAK packet received:
   1) If it is in slow start phase, set inter-packet interval to
      1/recvrate. Slow start ends. Stop.
   2) If this NAK starts a new congestion period, increase inter-packet
      interval (snd) to snd = snd * 1.125; Update AvgNAKNum, reset
      NAKCount to 1, and compute DecRandom to a random (average
      distribution) number between 1 and AvgNAKNum. Update LastDecSeq.
      Stop.
   3) If DecCount <= 5, and NAKCount == DecCount * DecRandom:
        a. Update SND period: SND = SND * 1.125;
        b. Increase DecCount by 1;
        c. Record the current largest sent sequence number (LastDecSeq).
 

 

发包函数:

发送算法:

1)如果丢失列表不为空,则重传这些packet包,并从丢失列表中移出,到5)
2)若应用层有数据,则执行发送
3) 进行检查
   a. 若未确认的包的数量超过流量窗口的大小,则回到1)
   b. 组织一个新的数据包,之后发送出去
4) 若当前的包的序号是16n(16的倍数),回到2),此处的作用是pair packet,可用于估计带宽的
5) 记录包的发送时间到SND PKT History Window中
6)如果属于发送速率降低后发送的第一个包,则等待SYN的时间
7) 得到STP-t的时间, t是step 1 to step 4 花费的时间. 回到 1).

算法的核心:
(1)为了保证可靠性,没有发送成功的包,需要重传
(2)可以发送的包数量受拥塞窗口和滑动窗口的限制
(3)根据发送速率的控制,两个包之间的发送时间间隔需要控制
 

代码实现

    long iterationStart;
    public void senderAlgorithm()throws InterruptedException, IOException{
        while(!paused){
            // 本次迭代的时间
            iterationStart=Util.getCurrentTime();
            // 步骤1):if the sender's loss list is not empty
            // 移出
            Long entry=senderLossList.getFirstEntry();
            if(entry!=null){
                // 执行重传
                handleRetransmit(entry);
            }
            else
            {
                // 步骤2) 若应用层有数据,则执行发送
                // 步骤3) 进行检查
                //if the number of unacknowledged data packets does not exceed the congestion
                //and the flow window sizes, pack a new packet
                int unAcknowledged=unacknowledged.get();
               
                // 未确认的包的数量小于拥塞窗口大小和流控制窗口
                if(unAcknowledged                         && unAcknowledged                     //check for application data
                    DataPacket dp=flowWindow.consumeData();
                    if(dp!=null){
                        send(dp);
                        largestSentSequenceNumber=dp.getPacketSequenceNumber();
                    }
                    else{
                        statistics.incNumberOfMissingDataEvents();
                    }
                }else{
                    //congestion window full, wait for an ack
                    if(unAcknowledged>=session.getCongestionControl().getCongestionWindowSize()){
                        statistics.incNumberOfCCWindowExceededEvents();
                    }
                   
                    // udt-java自己加入的处理方式
                    waitForAck();
                }
            }
            //wait
            if(largestSentSequenceNumber % 16 !=0){
                //发送时间间隔控制
                long snd=(long)session.getCongestionControl().getSendInterval();
                long passed=Util.getCurrentTime()-iterationStart;
                int x=0;
                while(snd-passed>0){
                    //can't wait with microsecond precision :(
                    if(x==0){
                        statistics.incNumberOfCCSlowDownEvents();
                        x++;
                    }
                    passed=Util.getCurrentTime()-iterationStart;
                    if(stopped)return;
                }
            }
        }
    }

拥塞控制算法实现

在UDT的实现中暴露了一些额外的参数给用户。用户自定义的拥塞控制算法中使用这些参数来调整包的发送速度。
下面的控制事件可以通过CCC进行重定义(例如,通过一个回调函数)
1)init:当UDT socket 建立连接时调用
2)close:当UDT socket关闭时调用
3)onACK:当收到ACK时调用
4)onLOSS:当收到NAK时调用
5)onTImeout:当定时器超时时调用
6)onPktSent:当发送数据包的时候调用
7)onPktRecv:当收到数据包的时候调用

 

你可能感兴趣的:(网络协议)