关闭

Aria2源代码分析——aria2 1.19.2

标签: aria2c++bittorrent
1032人阅读 评论(0) 收藏 举报
Aria2源代码分析-aria2.1.19.2

1.src/main.cc
主程序入口,从命令行接受启动参数,判断系统类型,调用不同的context构造函数

2.context类/结构
Context(bool standalone, int argc, char** argv, const KeyVals& options);
standalone /*没搞懂这个变量的意义,但是目测在openwrt下就是true,不需要特意关注*/
KeyVals& options /*KeyVals是一个自定义指针,类似于字典的格式,对组.
 The type of Key/Value pairs.*/
typedef std::vector<std::pair<std::string, std::string> > KeyVals;

3.context构造函数实现,首先调用option_processing函数,基本就是解析启动参数,不用关注细节。
之后根据协议类型调用,判断是BT 是url 还是磁力链接
只分析BT 输入参数为 本地目录torrent文件,非URL,如此则调用createRequestGroupForBitTorrent

4.createRequestGroupForBitTorrent
/*这个做了一个重构函数,针对输入的是url的torrent地址或者是xxx.torrent文件,总之最终都转化为种子文件名*/
但是adjustAnnounceUri没有传值???之后又继续作为参数往下传递了??
之后调用createBtRequestGroup

5.createBtRequestGroup
/*adjustAnnounceUri在此函数中作为入参直接赋值为true,不清楚原因*/
auto rg = std::make_shared<RequestGroup>(gid, option);
auto dctx = std::make_shared<DownloadContext>();
/*这里创建了两个类指针,从而调用其构造函数*/
5.1 RequestGroup
构造函数初始化了一些下载用的参数,调用了两个初始化函数,继续深入……
initializePreDownloadHandler();
initializePostDownloadHandler();
/* 初始化下载句柄。。获取了BT下载的句柄*/
getBtPreDownloadHandler,getBtPostDownloadHandler
5.2 DownloadContext
设定一些下载参数,看命名应该是比如,文件大小,分片之类的

6.main.cc 之前遗漏。。,程序最重要的执行入口。。。
  if(context.reqinfo) {
    exitStatus = context.reqinfo->execute();
  }
  std::shared_ptr<MultiUrlRequestInfo> reqinfo;
/*因此首先调用MultiUrlRequestInfo中的 excute*/

7.error_code::Value MultiUrlRequestInfo::execute()
     try {
    e_->run();
  } catch(RecoverableException& e) 
  这里, e_是 std::unique_ptr<DownloadEngine> e_;
  所以接下来调用DownloadEngine中的 run

8.int DownloadEngine::run(bool oneshot)
    /*此cc中 run()->excuteCommand()->excute()
    这里的excute我觉得是 bool AbstractCommand::execute()
    此处是父类(抽象类?)的excute,根据命令的类型,去判断触发哪种下载模式的excute()???猜测
    这里用到了getDownloadEngine
    之前的一系列构造函数调用和初始化中,有调用到其对应的set宏*/

    /*AbstractCommand::execute(),基类的excute,其余所有子类继承之*/  

9.bool AbstractCommand::execute()
    这里是下载真正执行的地方:
    e_->poolSocket(req_, createProxyRequest(), socket_);
    DownLoadEngine poolSocket()此函数为下载 socket 线程池??重构四个形态
    SocketPoolEntry e(sock, std::move(timeout));
  poolSocket(createSockPoolKey(ipaddr, port, A2STR::NIL,proxyhost,proxyport),e);

10.纠正8中的excute问题, 原调用形式如下:
for(size_t i = 0; i < max; ++i) {
    auto com = std::move(commands.front());
    commands.pop_front();
    if (!com->statusMatch(statusFilter)) {
      com->clearIOEvents();
      commands.push_back(std::move(com));
      continue;
    }
    com->transitStatus();
    if (com->execute()) {
      com.reset();
    }
    else {
      com->clearIOEvents();
      com.release();
    }
  }
/*com是自动类型,因此这里调用的excute具体是哪个类中的excute完全看获取到的command,所以既可能是调用
基类AbstractCommand中的excute,也可能是bool FillRequestGroupCommand::execute()
纠正错误。AbstractCommand并非基类。。基类是Command。。。AbstractCommand DownLoadCommand 
FillRequestGroupCommand等等全是Command的子类*/

11.纠正前面的错误。。。。  AbstractCommand。。这个这个,应该列出一个从Command开始的类继承关系图。。
然而种类太多了。。。一一列举不能
那么关注此子类     PeerAbstractCommand
它的子类   PeerInitiateConnectionCommand
bool PeerInitiateConnectionCommand::executeInternal() {
  A2_LOG_INFO(fmt(MSG_CONNECTING_TO_SERVER,
                  getCuid(),
                  getPeer()->getIPAddress().c_str(),
                  getPeer()->getPort()));
  createSocket();
  getSocket()->establishConnection(getPeer()->getIPAddress(),
                                   getPeer()->getPort(), false);
这里创建了socket连接。。。    

12.继续探究Command基类的子类,发现TrackerWatcherCommand这个类应当是BT下载的实现
它的excute中 
if(!trackerRequest_) {
    trackerRequest_ = createAnnounce(e_);//此处是创建一个客户端宣告信息,貌似

下面看上去是轮询所有的tracker信息,每个tracker服务器都尝试去连接。。  
那么问题来了。。。种子解析在哪。。。

13.种子解析在之前提到过的context构造函数中……好吧,搞清楚了。。
#ifdef ENABLE_BITTORRENT
  if(!op->blank(PREF_TORRENT_FILE)) {
    if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) {
      showTorrentFile(op->get(PREF_TORRENT_FILE));
      return;
    } else {
      createRequestGroupForBitTorrent(requestGroups, op, args,
                                      op->get(PREF_TORRENT_FILE));
    }
  }
/*是的。。就是这一段,blank是判断传进的字符串是否为空,这里的话就是判断你给没给torrent文件吧。。
op->get 是取那个参数的值。。那些宏都是Prefer指针。。有的是数字,有的是字符串,有的是true or false
详细的见Prefers.cc  就是属性(preferance)定义。。看文件的大概意思,应该是把这些不同的值,都归类为Pref指针
然后搞了一个数组把它们都串起来,抽象为一个id,或者一个key值。。你调用的aria2的时候应该给的就是关键字或者
id,然后程序自动转换成其所代表的意义。。。。大概是这样*/

/*言归正传,这里先判断了是否提供了torrent文件,之后判断你要做的是什么操作。。如果是show-file操作,
那么解析这个种子文件并且返回种子文件的内容。。什么uri啦。。announce啦。。等等,都给你打印在屏幕上吧
如果不是show-file,那么就创建RequestGroup了,在这里就有种子文件的解析。。*/
show-file分支,解析调用的是bittorrent::load()
createRequestGroup分支,调用的是 bittorent::LoadFromMemory()
他们都定义在 bittorent_helper.cc
仔细读一下就发现,其实这两个函数都是调用了bittorent::processRootDictionary()这个函数。。
这里就是详细的解析。。然后如果是create的动作,那么相关的信息,存储到 DownloadContext和TorrentAttribute
这两个类

14.到这里我觉得大致的BT下载框架解析完毕。。可以看到aria2用的是udp打洞(具体的可以看NAT穿越)来做P2P通信,
并没有用现成的bittorrent库之类的,但是基本思想是照抄的,即 client-tracker-client模式

15.如果还需要深入研究各种功能。。最好的办法我觉得是 从Command这一基类,找到它的子类。。挨个分析,树状遍历       
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7113次
    • 积分:104
    • 等级:
    • 排名:千里之外
    • 原创:3篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档