工具类分析-rak::ChunkStatistics

来源:互联网 发布:目前最火爆的网络手游 编辑:程序博客网 时间:2024/06/10 19:30

P2P的核心特点决定了P2P必须从多个peer下载,这样必然要求将下载的内容分段-chunk,在这些chunk中先下哪一个呢?或者说哪一个chunk最宝贵呢,市场经济早就告诉了我们,物以稀为贵。这也是BT chunk选择算法最重要最基本的,当然在不同的应用中还会加上一些权重(比如视音频的索引chunk,谁让人家是衔玉而生呢),为了确定稀缺度,我们需要进行精确的汇总统计,torrent::ChunkStatistics 类就完成这个工作.

原型: class ChunkStatistics: public std::vector<uint8_t>

说明: vector派生类,下标为chunk index, 值为“市场上”货物数目,如[1]=10 表示index为1的chunk有10个peer拥有。既然是统计chunk数的,其必然是归download,所有peer共享一个,在实际中是DownloadMain的成员变量m_chunkStatistics

调用时机:在BT协议中,当peer握手成功后,交换bitfield会调用received_connect;在收到HAV Message时会调用received_have_chunk;在Peer断开时会调用received_disconnect。

注意:因为是 uint8_t的vector,这表示最大的统计数是 255个,由函数 should_add(PeerChunks* pc) 进行检查

成员变量:

   size_type           m_complete;      //拥有所有chunk的peer数,即seeder数 
 
size_type           m_accounted;    //拥有部分chunk的peer数,即leecher数

核心函数:

//初始化vector 大小,参数:chunk 数目 ,由 DownloadMain::open调用
void ChunkStatistics::initialize(size_type s) {
  if(!empty())
    throwinternal_error("ChunkStatistics::initialize(...) called on an initialized object.");

  base_type::resize(s);
}

//PeerConnectionBase::initialize 函数中调用,pc->using_counter记录是否被统计过void ChunkStatistics::received_connect(PeerChunks* pc) {  if (pc->using_counter())    throw internal_error("ChunkStatistics::received_connect(...) pc->using_counter() == true.");    //peer是seeder  if (pc->bitfield()->is_all_set()) {    pc->set_using_counter(true);    m_complete++;  } else if (!pc->bitfield()->is_all_unset() && should_add(pc)) {    //peer是leech    pc->set_using_counter(true);    m_accounted++;        iterator itr = base_type::begin();    //加    for (Bitfield::size_type index = 0; index < pc->bitfield()->size_bits(); ++index, ++itr)      *itr += pc->bitfield()->get(index);  }}
//PeerConnectionBase::cleanup调用voidChunkStatistics::received_disconnect(PeerChunks* pc) {  //没有统计过.  if (!pc->using_counter())    return;  pc->set_using_counter(false);  if (pc->bitfield()->is_all_set()) {    m_complete--;  } else {    if (m_accounted == 0)      throw internal_error("ChunkStatistics::received_disconnect(...) m_accounted == 0.");    m_accounted--;    iterator itr = base_type::begin();    //减.    for (Bitfield::size_type index = 0; index < pc->bitfield()->size_bits(); ++index, ++itr)      *itr -= pc->bitfield()->get(index);  }}//PeerConnection::read_have_chunk(uint32_t index) 调用voidChunkStatistics::received_have_chunk(PeerChunks* pc, uint32_t index, uint32_t length) {  // When the bitfield is empty, it is very cheap to add the peer to  // the statistics. It needs to be done here else we need to check if  // a connection has sent any messages, else it might send a bitfield.  if (pc->bitfield()->is_all_unset() && should_add(pc)) {    if (pc->using_counter())      throw internal_error("ChunkStatistics::received_have_chunk(...) pc->using_counter() == true.");    pc->set_using_counter(true);    m_accounted++;  }  pc->bitfield()->set(index);  pc->peer_rate()->insert(length);    if (pc->using_counter()) {    base_type::operator[](index)++;    //peer由leech 转变为 seeder     if (pc->bitfield()->is_all_set()) {      if (m_accounted == 0)    throw internal_error("ChunkStatistics::received_disconnect(...) m_accounted == 0.");            m_complete++;      m_accounted--;            for (iterator itr = base_type::begin(), last = base_type::end(); itr != last; ++itr)    *itr -= 1;    }  } else {    if (pc->bitfield()->is_all_set()) {      pc->set_using_counter(true);      m_complete++;    }  }}
   //获得index的统计数  const_reference     rarity(size_type n) const       { return base_type::operator[](n); }  const_reference     operator [] (size_type n) const { return base_type::operator[](n); }
原创粉丝点击