专栏首页毛毛v5libaria2: C++ library interface to HTTP(S), FTP, SFTP, BitTorrent, and Metalink

libaria2: C++ library interface to HTTP(S), FTP, SFTP, BitTorrent, and Metalink

aria2 is a utility for downloading files. The supported protocols are HTTP(S), FTP, SFTP, BitTorrent, and Metalink. aria2 can download a file from multiple sources/protocols and tries to utilize your maximum download bandwidth. It supports downloading a file from HTTP(S)/FTP /SFTP and BitTorrent at the same time, while the data downloaded from HTTP(S)/FTP/SFTP is uploaded to the BitTorrent swarm. Using Metalink chunk checksums, aria2 automatically validates chunks of data while downloading a file.

This section is a step by step guide to create a program to download files using libaria2. The complete source is located at libaria2ex.cc in examples directory.

The libaria2ex program takes one or more URIs and downloads each of them in parallel. The usage is:

Usage: libaria2ex URI [URI...]

Download given URIs in parallel in the current directory. The source code uses C++11 features, so C++11 enabled compiler is required. GCC 4.7 works well here.

OK, let’s look into the source code. First, include aria2.h header file:

#include <aria2/aria2.h>

Skip to the main() function. After checking command-line arguments, we initialize libaria2:

aria2::libraryInit();

And create aria2 session object:

aria2::Session* session;
// Create default configuration. The libaria2 takes care of signal
// handling.
aria2::SessionConfig config;
// Add event callback
config.downloadEventCallback = downloadEventCallback;
session = aria2::sessionNew(aria2::KeyVals(), config);

Session session is an aria2 session object. You need this object through out the download process. Please keep in mind that only one Session object can be allowed per process due to the heavy use of static objects in aria2 code base. Session object is not safe for concurrent accesses from multiple threads. It must be used from one thread at a time. In general, libaria2 is not entirely thread-safe. SessionConfig config holds configuration for the session object. The constructor initializes it with the default values. In this setup, SessionConfig::keepRunning is false which means run() returns when all downloads are processed, just like aria2c utility without RPC enabled. And SessionConfig::useSignalHandler is true, which means libaria2 will setup signal handlers and catches certain signals to halt download process gracefully. We also setup event handler callback function downloadEventCallback. It will be called when an event occurred such as download is started, completed, etc. In this example program, we handle 2 events: download completion and error. For each event, we print the GID of the download and several other information:

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) << "] ";
  ...
}

The userData object is specified by SessionConfig::userData. In this example, we don’t specify it, so it is nullptr.

The first argument to sessionNew() is aria2::KeyVals(). This type is used in API to specify vector of key/value pairs, mostly representing aria2 options. For example, specify an option file-allocation to none:

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

The first argument of sessionNew() is analogous to the command-line argument to aria2c program. In the example program, we provide no options, so just pass empty vector.

After the creation of session object, let’s add downloads given in the command-line:

// Add download item to session
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 << "Failed to add download " << uris[0] << std::endl;
  }
}

We iterate command-line arguments and add each of them as a separate download. addUri() can take one or more URIs to download several sources, just like aria2c does, but in this example, we just give just one URI. We provide no particular option for the download, so pass the empty vector as options. The second argument of addUri() takes a pointer to A2Gid. If it is not NULL, the function assigns the GID of the new download to it. In this example code, we have no interest for it, so just pass nullptr.

We have set up everything at this stage. So let’s start download. To perform the download, call run() repeatedly until it returns the value other than 1:

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

Here, we call run() with RUN_ONCE. It means run() returns after one event polling and its action handling or polling timeout (which is approximately 1 second). If run() returns 1, it means the download is in progress and the application must call it again. If it returns 0, then no download is left (or it is stopped by signal handler or shutdown()). If the function catches error, it returns -1. The good point of using RUN_ONCE is that the application can use libaria2 API when run() returns. In the example program, we print the progress of the download in every no less than 500 millisecond:

// Print progress information once per 500ms
if(count >= 500) {
  start = now;
  aria2::GlobalStat gstat = aria2::getGlobalStat(session);
  std::cerr << "Overall #Active:" << gstat.numActive
            << " #waiting:" << 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);
    }
  }
}

We first call getGlobalStat() function to get global statistics of the downloads. Then, call getActiveDownload() function to get the vector of active download’s GID. For each GID, we retrieve DownloadHandle object using getDownloadHandle() function and get detailed information. Please don’t forget to delete DownloadHandle after the use and before the next call of run(). Keep in mind that the life time of DownloadHandle object is before the next call of run() function.

After the loop, finalize download calling sessionFinal() function and call libraryDeinit() to release resources for the library:

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

Calling sessionFinal() is important because it performs post-download action, including saving sessions and destroys session object. So failing to call this function will lead to lose the download progress and memory leak. The sessionFinal() returns the code defined in EXIT STATUS. aria2c program also returns the same value as exist status, so do the same in this tiny example program.

See also libaria2wx.cc which uses wx GUI component as UI and use background thread to run download.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 附004.Kubernetes Dashboard简介及使用

    dashboard是基于Web的Kubernetes用户界面。可以使用dashboard将容器化应用程序部署到Kubernetes集群,对容器化应用程序进行故障...

    木二
  • 附006.Kubernetes RBAC授权

    基于角色的访问控制(RBAC)是一种基于个人用户的角色来管理对计算机或网络资源的访问的方法。

    木二
  • 衡量视频质量有哪些指标和工具?

    https://www.streamingmedia.com/Articles/Editorial/Featured-Articles/Buyers-Guide...

    LiveVideoStack
  • Apple 低延迟HLS分析

    HTTP Live Streaming(HLS)是Apple公司主导提出并实现的基于HTTP的自适应码率流媒体通信协议(RFC8216),作为其产品QuickT...

    LiveVideoStack
  • 基于Bootstrap的Metro风格模板

    版权声明:本文为[他叫自己Mr.张]的原创文章,转载请注明出...

    他叫自己MR.张
  • 附005.Kubernetes身份认证

    与Kubernetes交互通常有kubectl、客户端(Dashboard)、REST API请求。

    木二
  • 006.Ceph对象存储基础使用

    Ceph 对象网关是一个构建在 librados 之上的对象存储接口,它为应用程序访问Ceph 存储集群提供了一个 RESTful 风格的网关 。

    木二
  • 机器学习无从下手?整理的这些清单可以助你一臂之力!

    source:https://github.com/FavioVazquez/ds-cheatsheets

    1480
  • 训练文本识别器,你可能需要这些数据集

    我们知道,监督式深度学习非常依赖于带标签的数据集,通常数据集越大,训练出的模型效果越好,对于文本检测和识别也是如此,为了训练出好的模型,我们需要大型数据集。然而...

    云水木石
  • Android必知必会-Stetho调试工具

    版权声明:本文为[他叫自己Mr.张]的原创文章,转载请...

    他叫自己MR.张

扫码关注云+社区

领取腾讯云代金券