quic协议栈之fec

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010643777/article/details/89289519

 quic最初的版本里有fec算法,含有fec的老代码,可以在这里看到[1]。这个特性在很早就被移除了,虽说当时是作为一个feature来宣传的。移除的原因一,采用简单的XOR作为FEC方案,面对burst丢包,恢复能力有限,二是在没有丢包的时候,FEC冗余包的发送是一种资源浪费,三是当前网络中的丢包率应该是很低的[2]。
 在16年的时候,我有次观看YouTube视频,用wireshark抓包,发现一个之前不知道的协议。就查了点资料,它的文档里有多径的定义。多径传输的研究,是我们实验室的研究点。虽然,多径传输的特性也被放弃了。那个时候,quic在国内还不太火,我阅读代码的能力也很有限,也就放下了。
 就简单说明下这部分的代码处理流程,作为一个记录。
 fec开关开启:

void QuicPacketGenerator::MaybeStartFecProtection() {
packet_creator_.StartFecProtectingPackets();
}
void QuicPacketCreator::StartFecProtectingPackets() {
should_fec_protect_ = true;
}

 quic协议的头部需要携带fec的信息,当前的stream帧是否采用了fec,是在哪个fec分组中。

struct  QuicPacketHeader {
  bool fec_flag;
  InFecGroup is_in_fec_group;
  QuicFecGroupNumber fec_group;
}

 对数据包序列化的时候,需要为header加上相应的信息。

SerializedPacket QuicPacketCreator::SerializePacket(
    char* encrypted_buffer,
    size_t encrypted_buffer_len) {
      QuicPacketHeader header;
  FillPacketHeader(should_fec_protect_ ? fec_group_number_ : 0, false, &header);
  //XOR operation,记录fec包中内容
    OnBuiltFecProtectedPayload(header, packet->FecProtectedData());
}

 fec数据包的序列化

void QuicPacketGenerator::MaybeSendFecPacketAndCloseGroup(bool force,
                                                          bool is_fec_timeout){
   if (!ShouldSendFecPacket(force)) {
    return;
  }                                                         
    char buffer[kMaxPacketSize];
    SerializedPacket serialized_fec =
        packet_creator_.SerializeFec(buffer, kMaxPacketSize);
    DCHECK(serialized_fec.packet);
    delegate_->OnSerializedPacket(serialized_fec);                                                          
}                                                          

 :MaybeSendFecPacketAndCloseGroup这个函数的执行似乎是由一个定时器fec_alarm_驱动的。ShouldSendFecPacket(force)这个判断,是否发送fec数据包。其中有一项就是每十个(max_packets_per_fec_group_)数据包生成一个fec包。

bool QuicPacketGenerator::ShouldSendFecPacket(bool force) {
  return packet_creator_.IsFecProtected() &&
         !packet_creator_.HasPendingFrames() &&
         packet_creator_.ShouldSendFec(force);
}
bool QuicPacketCreator::ShouldSendFec(bool force_close) const {
  DCHECK(!HasPendingFrames());
  return fec_group_.get() != nullptr && fec_group_->NumReceivedPackets() > 0 &&
         (force_close ||
          fec_group_->NumReceivedPackets() >= max_packets_per_fec_group_);
}

 而AddFrame函数负责将数据包保存到queued_retransmittable_frames_,这个类中的数据在数据包序列化的时候,被转移到了SerializedPacket。若是发生丢包,QuicSentPacketManager::PendingRetransmission就可以进行重传。

bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
                                 bool save_retransmittable_frames,
                                 bool needs_padding,
                                 char* buffer) {
  if (save_retransmittable_frames && ShouldRetransmit(frame)) { //如果frame需要进行retransmit
    if (queued_retransmittable_frames_.get() == nullptr) { 
      queued_retransmittable_frames_.reset( //new RetransmittableFrames类
          new RetransmittableFrames(encryption_level_));
    }

	//frame和buffer分别加入到RetransmittableFrames类的stream_data_容器和frame_容器,同时把frame加入到queued_frames_队列
	//也就是如果frame需要重传则除了入队到queued_frames_队列外,还要入队到queued_retransmittable_frames_
    queued_frames_.push_back(
        queued_retransmittable_frames_->AddFrame(frame, buffer));
  } else {
    queued_frames_.push_back(frame);
  }                                 
}
SerializedPacket QuicPacketCreator::SerializePacket(
    char* encrypted_buffer,
    size_t encrypted_buffer_len) {  
  return SerializedPacket(header.packet_sequence_number,
                          header.public_header.sequence_number_length,
                          encrypted, QuicFramer::GetPacketEntropyHash(header),
                          queued_retransmittable_frames_.release());    
    }                               
size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
                                            const QuicIOVector& iov,
                                            size_t iov_offset,
                                            QuicStreamOffset offset,
                                            bool fin,
                                            QuicFrame* frame,
                                            scoped_ptr<char[]>* buffer)
{
//判断是否要重置fec_group_
  InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec();
}                                            

[1] quic fec https://github.com/y123456yz/reading-and-annotate-quic/tree/master/libquic-client-server-example/libquic/src/net/quic
[2] Compare packets loss rate of BBR and CUBIC on ns3

展开阅读全文

没有更多推荐了,返回首页