1、功能:实现带宽评估、发送窗口决策、RTT与RTC的计算。
2、成员函数解析。
[1].处理接收到的ACK。
void RUDPCCCObject::on_ack(uint64_t ack_seq)
{
if(ack_seq <= last_ack_id_)
{
return;
}
uint32_t space = (uint32_t)(ack_seq - last_ack_id_);
if(slow_start_) //慢启动窗口决策
{
snd_cwnd_ += space;
if(snd_cwnd_ >= max_cwnd_)
{
slow_start_ = false;
RUDP_INFO("ccc stop slow_start, snd_cwnd = " << snd_cwnd_);
snd_cwnd_ = max_cwnd_;
}
RUDP_DEBUG("send window size = " << snd_cwnd_);
}
//RUDP_DEBUG("onack, seq = " << ack_seq);
last_ack_id_ = ack_seq;
}
首先检查ACK的ID的合法性,若ACK的ID是非法的,则不处理当前ACK。否则,启动慢窗口决策并更新zui最新收到的ACK包的ID。
[2].处理接收到的nack。
void RUDPCCCObject::on_loss(uint64_t base_seq, const LossIDArray& loss_ids)
{
if(slow_start_) //取消慢启动
{
slow_start_ = false;
RUDP_INFO("ccc stop slow_start, snd_cwnd = " << snd_cwnd_);
}
}
这里主要是取消慢启动策略。
[3].设置滑动窗口的最大尺寸。
void RUDPCCCObject::set_max_cwnd(uint32_t rtt)
{
if (rtt < 10) //吞吐量上限设置
max_cwnd_ = 512;
else if (rtt < 50)
max_cwnd_ = 1024;
else if (rtt < 100)
max_cwnd_ = 1024 + 256;
else if (rtt <= 200)
max_cwnd_ = 1024 + 512;
else{
max_cwnd_ = 1024;
}
limit_cwnd_ = 128;
}
这里主要是依据rtt的值来计算发送方滑动窗口的最大值,同时将发送方滑动窗口的最小值设置为128 。
[4].速率控制器的定时事件。
void RUDPCCCObject::on_timer(uint64_t now_ts)
{
//delay 不小于 100ms
uint32_t delay = core_max(rtt_ * 4, 100);
if (now_ts >= prev_on_ts_ + delay) //10个RTT决策一次
{
print_count_ ++;
if(print_count_ % 4 == 0)
{
set_max_cwnd(rtt_);
}
if(slow_start_) //停止慢启动过程
{
if(print_count_ > 10)
{
slow_start_ = false;
RUDP_INFO("ccc stop slow_start, snd_cwnd = " << snd_cwnd_);
}
}
else
{
if (recv_count_ / 16 > resend_count_)
{
snd_cwnd_ = (uint32_t)(snd_cwnd_ + core_max(8, (snd_cwnd_ / 8)));
snd_cwnd_ = core_min(max_cwnd_, snd_cwnd_);
}
else if (recv_count_ / 4 < resend_count_){
snd_cwnd_ = (uint32_t)(snd_cwnd_ - (snd_cwnd_ / 4));
snd_cwnd_ = core_max(min_cwnd_, snd_cwnd_);
loss_flag_ = true;
if (snd_cwnd_ < limit_cwnd_)
min_cwnd_ = limit_cwnd_;
}
RUDP_DEBUG("send window size = " << snd_cwnd_ << ",rtt = " << rtt_ << ",rtt_var = " << rtt_var_ << ",resend = " << resend_count_ << "recv count = " << recv_count_);
resend_count_ = 0;
recv_count_ = 0;
}
prev_on_ts_ = now_ts;
loss_flag_ = false;
}
}
此成员函数实现慢启动、发送窗口动态调整决策。这个成员函数每四个delay时间段调整最大发送窗口与最小发送窗口,初始时,是十个delay之前是慢启动的过程,十个delay之后是动态调整发送窗口的尺寸并更新最小发送窗口。若在在这段时间内(10个delay),接收数据片的数量是重发的数据片的数量的16倍以上,则扩大滑动窗口。
if (recv_count_ / 16 > resend_count_)
{
snd_cwnd_ = (uint32_t)(snd_cwnd_ + core_max(8, (snd_cwnd_ / 8)));
snd_cwnd_ = core_min(max_cwnd_, snd_cwnd_);
}
若接收 数据片的数量/重发数据片的数量<4,则缩小滑动窗口的尺寸。并更新滑动窗口的最小值。
else if (recv_count_ / 4 < resend_count_){
snd_cwnd_ = (uint32_t)(snd_cwnd_ - (snd_cwnd_ / 4));
snd_cwnd_ = core_max(min_cwnd_, snd_cwnd_);
loss_flag_ = true;
if (snd_cwnd_ < limit_cwnd_)
min_cwnd_ = limit_cwnd_;
}
重置接收数据片与重发的数据片的数量。之后是每过一个delay就要动态调整发送窗口的尺寸并更新最小发送窗口。
[5].设置rtt_(往返时延)与rtt_var_(一个数据片从发送端发送到接收端接收的时间)。
void RUDPCCCObject::set_rtt(uint32_t keep_live_rtt)
{
//提高高延迟网络的吞吐量(BDP)
if(max_cwnd_ == DEFAULT_CWND_SIZE)
set_max_cwnd(keep_live_rtt);
//计算rtt和rtt修正
if(rtt_first_)
{
rtt_first_ = false;
rtt_ = keep_live_rtt;
rtt_var_ = rtt_ / 2;
}
else //参考了tcp的rtt计算
{
rtt_var_ = (rtt_var_ * 3 + core_abs(rtt_, keep_live_rtt)) / 4;
rtt_ = (7 * rtt_ + keep_live_rtt) / 8;
}
//rtt_与rtt_var_不能小于1ms
rtt_ = core_max(1, rtt_);
rtt_var_ = core_max(1, rtt_var_);
}
设置rtt。首次计算时,
//计算rtt和rtt修正
if(rtt_first_)
{
rtt_first_ = false;
rtt_ = keep_live_rtt;
rtt_var_ = rtt_ / 2;
}
即将keep_live_rtt赋值给rtt_,将keep_alive_rtt的一半赋值给rtt_var_。
以后的rtt_与rtt_var_的计算则参考了TCP。
else //参考了tcp的rtt计算
{
rtt_var_ = (rtt_var_ * 3 + core_abs(rtt_, keep_live_rtt)) / 4;
rtt_ = (7 * rtt_ + keep_live_rtt) / 8;
}
即rtt_var_=3/4rtt_var_+1/4abs(rtt_-keep_live_rtt);
rtt_=7/8rtt+1/8(keep_live_rtt)