libaria2:C++库接口到aria2

Warning

API尚未固定。它将在开发过程中被更改。

libaria2是一个C++库,提供aria2的核心功能。该库处理所有网络和下载相关的事务, 所以它的使用现在非常直接。查看以下教程部分了解如何使用API。

教程

本节是逐步指导创建一个使用libaria2下载文件的程序。完整的源代码位于 examples 目录下的 libaria2ex.cc

libaria2ex 程序接受一个或多个URI,并且并行下载每个 文件。使用方式如下:

使用方式: libaria2ex URI [URI…]

在当前目录下并行下载给定的URI。

源代码使用C++11特性,因此需要支持C++11的编译器。 GCC 4.7在这里工作良好。

好的,让我们来看看源代码。首先,包含aria2.h头文件:

#include <aria2/aria2.h>

跳转到 main() 函数。在检查命令行 参数后,我们初始化libaria2:

aria2::libraryInit();

并创建aria2会话对象:

aria2::Session* session;
// 创建默认配置。libaria2处理信号
// 处理。
aria2::SessionConfig config;
// 添加事件回调
config.downloadEventCallback = downloadEventCallback;
session = aria2::sessionNew(aria2::KeyVals(), config);

Session session 是一个aria2会话对象。您需要这个 对象贯穿整个下载过程。请记住,由于在aria2代码库中大量使用静态对象,每个进程只允许一个:type:Session`对象。:type:`Session`对象不适用于从多个线程并发访问。它必须一次从一个线程使用。一般来说,libaria2并不是完全线程安全的。:type:`SessionConfig config 保存会话对象的配置。构造函数使用默认值初始化它。在此设置中,SessionConfig::keepRunningfalse 表示当所有下载都处理完毕时 run() 返回,就像没有启用RPC的aria2c工具一样。并且 SessionConfig::useSignalHandlertrue,意味着libaria2将设置信号处理器并捕获某些信号以优雅地停止下载过程。我们还设置了事件处理回调函数 downloadEventCallback。当发生事件时,比如下载开始、完成等,它将被调用。在这个示例程序中,我们处理了两个事件:下载完成和错误。对于每个事件,我们打印下载的GID和其他几个 信息:

int downloadEventCallback(aria2::Session* session, aria2::DownloadEvent event,
                          const aria2::A2Gid& gid, void* userData)
{
  switch(event) {
  case aria2::EVENT_ON_DOWNLOAD_COMPLETE:
    std::cerr << "COMPLETE";
    break;
  case aria2::EVENT_ON_DOWNLOAD_ERROR:
    std::cerr << "ERROR";
    break;
  default:
    return 0;
  }
  std::cerr << " [" << aria2::gidToHex(gid) << "] ";
  ...
}

userData 对象由 SessionConfig::userData 指定。在这个示例中,我们没有指定 它,所以它是 nullptr

sessionNew() 的第一个参数是 aria2::KeyVals()。 这个类型在API中用于指定键/值对的向量,大多表示aria2选项。例如,指定选项 file-allocationnone:

aria2::KeyVals options;
options.push_back(std::pair<std::string, std::string> ("file-allocation", "none"));

sessionNew() 的第一个参数类似于aria2c程序的 命令行参数。在示例程序中,我们没有提供任何选项,所以只需传递空向量。

在创建会话对象之后,让我们添加命令行中给出的下载:

// 将下载项添加到会话中
for(int i = 1; i < argc; ++i) {
  std::vector<std::string> uris = {argv[i]};
  aria2::KeyVals options;
  rv = aria2::addUri(session, nullptr, uris, options);
  if(rv < 0) {
    std::cerr << "添加下载失败 " << uris[0] << std::endl;
  }
}

我们迭代命令行参数并将每个参数作为一个单独的 下载添加。addUri() 可以接受一个或多个URI来下载 多个源,就像aria2c一样,但在这个例子中,我们只 给出了一个URI。我们没有为下载提供特定的选项, 所以传递空向量作为选项。addUri() 的第二个参数接受一个指向 A2Gid 的指针。如果它不是 NULL,函数会将新下载的GID分配给它。在 这个示例代码中,我们对它不感兴趣,所以只需传递 nullptr

到目前为止,我们已经设置好了一切。所以让我们开始下载。为了 执行下载,反复调用 run() 直到它返回 不是 1 的值:

for(;;) {
  rv = aria2::run(session, aria2::RUN_ONCE);
  if(rv != 1) {
    break;
  }
  ...
}

这里,我们用 RUN_ONCE 调用 run()。这意味着 run() 在一次事件轮询及其动作处理 或轮询超时(大约1秒)后返回。如果 run() 返回 1,意味着下载正在进行中,应用程序必须再次调用它。如果它返回 0,那么没有下载 剩余(或它被信号处理器或 shutdown() 停止)。 如果函数捕获错误,它返回 -1。使用 RUN_ONCE 的好处是应用程序可以在 run() 返回时使用libaria2 API。在示例程序中,我们每隔不少于500毫秒打印一次 下载进度:

// 每500ms打印一次进度信息
if(count >= 500) {
  start = now;
  aria2::GlobalStat gstat = aria2::getGlobalStat(session);
  std::cerr << "整体 #活跃:" << gstat.numActive
            << " #等待:" << gstat.numWaiting
            << " D:" << gstat.downloadSpeed/1024 << "KiB/s"
            << " U:"<< gstat.uploadSpeed/1024 << "KiB/s " << std::endl;
  std::vector<aria2::A2Gid> gids = aria2::getActiveDownload(session);
  for(const auto& gid : gids) {
    aria2::DownloadHandle* dh = aria2::getDownloadHandle(session, gid);
    if(dh) {
      std::cerr << "    [" << aria2::gidToHex(gid) << "] "
                << dh->getCompletedLength() << "/"
                << dh->getTotalLength() << "("
                << (dh->getTotalLength() > 0 ?
                    (100*dh->getCompletedLength()/dh->getTotalLength())
                    : 0) << "%)"
                << " D:"
                << dh->getDownloadSpeed()/1024 << "KiB/s, U:"
                << dh->getUploadSpeed()/1024 << "KiB/s"
                << std::endl;
      aria2::deleteDownloadHandle(dh);
    }
  }
}

我们首先调用 getGlobalStat() 函数来获取下载的全局 统计信息。然后,调用 getActiveDownload() 函数来获取活动下载的GID向量。对于每个GID,我们 使用 getDownloadHandle() 函数检索 DownloadHandle 对象并获取详细信息。 请不要忘记在使用后和下一次调用 run() 之前删除 DownloadHandle。请记住 DownloadHandle 对象的生命周期是在下一次调用 run() 之前。

循环结束后,调用 sessionFinal() 函数完成下载,并调用 libraryDeinit() 释放库的资源:

rv = aria2::sessionFinal(session);
aria2::libraryDeinit();
return rv;

调用 sessionFinal() 很重要,因为它执行下载后的操作,包括保存会话和销毁会话对象。因此,如果不调用此函数,将导致下载进度丢失和内存泄漏。sessionFinal() 返回在 退出状态 中定义的代码。aria2c 程序也返回相同的值作为退出状态,所以在这个小示例程序中也做同样的操作。

另请参见 libaria2wx.cc,它使用 wx GUI 组件作为用户界面,并使用后台线程运行下载。

API 参考

要使用 API 函数,请包含 aria2/aria2.h

#include <aria2/aria2.h>

所有枚举、类型和函数都在 aria2 命名空间下。要链接 libaria2,请使用链接器标志 -laria2