ltsession(會(huì)話)是最核心的,種子只有加入進(jìn)去方可下載上傳等動(dòng)作。session_handle: 主要負(fù)責(zé)對(duì)session的操作。
torrent_handle: 主要負(fù)責(zé)對(duì)種子的操作以及狀態(tài)查詢。

session.pop_alerts(): 可以獲取從上次調(diào)用以來(lái)的所有新警報(bào)的列表。每種特定類型的警報(bào)可能包括特定于消息類型的附加狀態(tài)。所有警報(bào)都實(shí)現(xiàn)一個(gè)message()函數(shù),該函數(shù)輸出警報(bào)消息的相關(guān)信息。這可以方便地記錄事件。
下面先針對(duì)各小功能進(jìn)行代碼實(shí)現(xiàn),最好再整合一個(gè)完整的代碼例子
1. 添加種子/磁力(并下載)lt::session ses; //定義session對(duì)象lt::add_torrent_params p = lt::parse_magnet_uri("magnet:?xt=urn:btih:......");// 解析磁力鏈接p.save_path = ".";// 設(shè)置保存到當(dāng)前目錄lt::torrent_handle h = ses.add_torrent(p); //添加到session,并獲得其句柄(該句阻塞執(zhí)行,有結(jié)果才返回)lt::session ses; //定義session對(duì)象auto ti = std::make_shared<lt::torrent_info>(torrentFilePath); //通過(guò)種子文件 定義 torrent_info對(duì)象lt::add_torrent_params p; p.ti = ti;//這兒很重要, 必須要中torrent_info對(duì)象傳遞進(jìn)來(lái)p.save_path = ".";p.userdata = static_cast<void*>(new std::string(torrentFilePath)); //這根據(jù)自己需要而定具體數(shù)據(jù)ses.async_add_torrent(std::move(p)); //這兒是異步調(diào)用, 調(diào)完就離開,獲取不到 session_handle以上為 通過(guò)磁力鏈接 和 torrent 種子這兩種方式添加到session的簡(jiǎn)單例子。torrent_info類又諸多構(gòu)造函數(shù),對(duì)象定義方法也因此非常多,根據(jù)需要選擇合適的。
另外添加種子到session的方法有 同步調(diào)用(阻塞耗時(shí))和異步調(diào)用(立即返回)兩種,也根據(jù)需要選擇。
2. 警報(bào)直接上代碼講解
for (;;) {std::vector<lt::alert*> alerts;ses.pop_alerts(&alerts);//獲取自上次調(diào)用以來(lái)的新警報(bào)列表for (lt::alert const* a : alerts) {//遍歷處理自己需要的警報(bào)。std::cout << a->message() << std::endl; //打印警報(bào)信息// 下面是針對(duì)各種類型的警報(bào)進(jìn)行處理例子if (lt::alert_cast<lt::torrent_finished_alert>(a)) {goto done;}if (lt::alert_cast<lt::torrent_error_alert>(a)) {goto done;}}std::this_thread::sleep_for(std::chrono::milliseconds(200));}done:std::cout << "done, shutting down" << std::endl;我們可以用‘警報(bào)掩碼’抓取我們關(guān)心的警報(bào)(有很多種類),如下 :
lt::settings_pack pack;pack.set_int(lt::settings_pack::alert_mask// 設(shè)置掩碼 關(guān)心 下面三種掩碼, lt::alert::error_notification| lt::alert::storage_notification| lt::alert::status_notification);lt::session ses(pack);警報(bào)掩碼 之 掩碼類別
警報(bào)類型
3. 更新配置選項(xiàng)session啟動(dòng)后,可以通過(guò)調(diào)用 apply_settings() 更新配置,
lt::settings_pack pack;pack.set_int(lt::settings_pack::alert_mask,lt::alert::status_notification);ses.apply_settings(pack);// 更新配置 alert_mask雖然這樣可以更新配置,但有些設(shè)置最好在啟動(dòng)會(huì)話之前設(shè)置,比如 listen_interfaces,以避免出現(xiàn)競(jìng)爭(zhēng)條件。如果使用默認(rèn)設(shè)置啟動(dòng)會(huì)話,然后立即更改它們,則仍會(huì)有一個(gè)應(yīng)用默認(rèn)設(shè)置的窗口。
更改設(shè)置可能會(huì)觸發(fā)偵聽套接字關(guān)閉和重新打開,并發(fā)送NAT-PMP、UPnP更新。因此,將設(shè)置更新批處理到單個(gè)調(diào)用中通常是一個(gè)好主意。
4. 獲取種子狀態(tài)for(;;){ses. post_torrent_updates();// 發(fā)送 alert::status_notificationstd::this_thread::sleep_for(250);std::vector<lt::alert*> alerts;ses.pop_alerts(&alerts);//獲取自上次調(diào)用以來(lái)的新警報(bào)列表for (lt::alert const* a : alerts) {//處理 state_update_alertif (state_update_alert* p = alert_cast<state_update_alert>(a)) {// 包含自上次調(diào)用以來(lái)更新的種子狀態(tài)std::vector<torrent_status> status = p->stauts;......}}....}5. 恢復(fù)種子恢復(fù)下載時(shí),BT引擎必須恢復(fù)正在下載種子的狀態(tài),特別是文件的哪些部分已下載, 有兩種方法可以做到這一點(diǎn):
(1) 從磁盤讀取已下載文件片段,并將其與預(yù)定的哈希值進(jìn)行比較。
(2) 保存已下載的片段(和部分片段)的狀態(tài)到磁盤,并在恢復(fù)時(shí)重新加載。
如果添加種子時(shí)沒(méi)有提供恢復(fù)數(shù)據(jù),那么libtorrent將默認(rèn)使用上面第1點(diǎn)。
libtorrent有提供函數(shù),實(shí)現(xiàn)保存恢復(fù)數(shù)據(jù)的功能:
torrent_handle.save_resume_data(torrent_handle::save_info_dict) ;調(diào)用該函數(shù)的時(shí)機(jī):
(1). 人為地選中某個(gè)種子,操作‘保存恢復(fù)數(shù)據(jù)’。
(2). 每個(gè)種子加載完成時(shí)。
(3). 關(guān)閉session之前。
注意:調(diào)用該函數(shù)并沒(méi)將恢復(fù)數(shù)據(jù)保存到磁盤上面, 調(diào)用該函數(shù)后實(shí)際上會(huì)發(fā)出警報(bào):
save_resume_data_alert(若成功) 或
save_resume_data_failed_alert(若失敗)
默認(rèn)情況下會(huì)話析構(gòu)函數(shù)會(huì)被阻塞。關(guān)閉時(shí),需要聯(lián)系追蹤器以停止種子,其他未完成的操作需要取消。關(guān)閉有時(shí)可能需要幾秒鐘,主要是因?yàn)楦櫰鳑](méi)有響應(yīng)(和超時(shí))以及DNS服務(wù)器沒(méi)有響應(yīng)。DNS查找在失控時(shí)尤其難以中止。
為了能夠異步地開始銷毀等待,可以調(diào)用session::abort()。它返回一個(gè)session_proxy對(duì)象,它是一個(gè)句柄,用于在銷毀會(huì)話狀態(tài)時(shí)保持會(huì)話狀態(tài)。它故意不提供任何會(huì)話操作,因?yàn)樗陉P(guān)閉。
擁有session_proxy對(duì)象后,會(huì)話析構(gòu)函數(shù)不會(huì)阻塞。但是session_proxy析構(gòu)函數(shù)卻將被阻塞。
這可用于并行關(guān)閉多個(gè)會(huì)話或應(yīng)用程序的其他部分。
7. 完整實(shí)例#include <iostream>#include <thread>#include <chrono>#include <fstream>#include <libtorrent/session.hpp>#include <libtorrent/add_torrent_params.hpp>#include <libtorrent/torrent_handle.hpp>#include <libtorrent/alert_types.hpp>#include <libtorrent/bencode.hpp>#include <libtorrent/torrent_status.hpp>#include <libtorrent/read_resume_data.hpp>#include <libtorrent/write_resume_data.hpp>#include <libtorrent/error_code.hpp>#include <libtorrent/magnet_uri.hpp>using clk = std::chrono::steady_clock;//返回 種子各種狀態(tài)的名稱char const* state(lt::torrent_status::state_t s){switch(s) {case lt::torrent_status::checking_files: return "checking";case lt::torrent_status::downloading_metadata: return "dl metadata";case lt::torrent_status::downloading: return "downloading";case lt::torrent_status::finished: return "finished";case lt::torrent_status::seeding: return "seeding";case lt::torrent_status::allocating: return "allocating";case lt::torrent_status::checking_resume_data: return "checking resume";default: return "<>";}}int main(int argc, char const* argv[]) try{if (argc != 2) {std::cerr << "usage: " << argv[0] << " <magnet-url>" << std::endl;return 1;}lt::settings_pack pack;pack.set_int(lt::settings_pack::alert_mask, lt::alert::error_notification| lt::alert::storage_notification| lt::alert::status_notification);lt::session ses(pack);clk::time_point last_save_resume = clk::now();// 從磁盤加載恢復(fù)數(shù)據(jù),并在添加磁力鏈接時(shí)傳遞它std::ifstream ifs(".resume_file", std::ios_base::binary);ifs.unsetf(std::ios_base::skipws);std::vector<char> buf{std::istream_iterator<char>(ifs) , std::istream_iterator<char>()};lt::add_torrent_params p = lt::read_resume_data(buf);lt::add_torrent_params magnet = lt::parse_magnet_uri(argv[1]);if (p.info_hash != magnet.info_hash) { //判斷恢復(fù)數(shù)據(jù)和磁力鏈接是否匹配,以磁力鏈接為準(zhǔn)p = std::move(magnet);}p.save_path = "."; // 保存到當(dāng)前目錄ses.async_add_torrent(std::move(p));lt::torrent_handle h;//當(dāng)我們收到add_torrent_alert時(shí),我們?cè)O(shè)置它for (;;) {std::vector<lt::alert*> alerts;ses.pop_alerts(&alerts);for (lt::alert const* a : alerts) {if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {h = at->handle;}// 如果收到 torrent_finished_alert或torrent_error_alert,則退出程序if (lt::alert_cast<lt::torrent_finished_alert>(a)) {h.save_resume_data();goto done;}if (lt::alert_cast<lt::torrent_error_alert>(a)) {std::cout << a->message() << std::endl;goto done;}// resume data準(zhǔn)備就緒,保存到磁盤文件if (auto rd = lt::alert_cast<lt::save_resume_data_alert>(a)) {std::ofstream of(".resume_file", std::ios_base::binary);of.unsetf(std::ios_base::skipws);auto const b = write_resume_data_buf(rd->params);of.write(b.data(), b.size());}if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {if (st->status.empty()) continue;// 因?yàn)槲覀冎挥幸粋€(gè)種子,所以我們知道 這個(gè)status是哪個(gè)種子的lt::torrent_status const& s = st->status[0];std::cout << "r" << state(s.state) << " "<< (s.download_payload_rate / 1000) << " kB/s "<< (s.total_done / 1000) << " kB ("<< (s.progress_ppm / 10000) << "%) downloadedx1b[K";std::cout.flush();}}std::this_thread::sleep_for(std::chrono::milliseconds(200));// post state_update_alert 更新種子輸出狀態(tài)ses.post_torrent_updates();// 每30秒保存恢復(fù)數(shù)據(jù)一次if (clk::now() - last_save_resume > std::chrono::seconds(30)) {h.save_resume_data();last_save_resume = clk::now();}}// 理想情況下,我們應(yīng)該在這里保存恢復(fù)數(shù)據(jù)done:std::cout << "ndone, shutting down" << std::endl;}catch (std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}
步驚云