BT磁力搜索引擎「torrent磁力種子搜索」

ltsession(會話)是最核心的,種子只有加入進去方可下載上傳等動作。

session_handle: 主要負責對session的操作。

torrent_handle: 主要負責對種子的操作以及狀態查詢。

session.pop_alerts(): 可以獲取從上次調用以來的所有新警報的列表。每種特定類型的警報可能包括特定於消息類型的附加狀態。所有警報都實現一個message()函數,該函數輸出警報消息的相關信息。這可以方便地記錄事件。

下面先針對各小功能進行代碼實現,最好再整合一個完整的代碼例子

1. 添加種子/磁力(並下載)

lt::session ses; 									//定義session對象
lt::add_torrent_params p = lt::parse_magnet_uri("magnet:?xt=urn:btih:......");        // 解析磁力鏈接
p.save_path = ".";                                     // 設置保存到當前目錄
lt::torrent_handle h = ses.add_torrent(p); //添加到session,並獲得其句柄(該句阻塞執行,有結果才返回)
lt::session ses; 									//定義session對象
auto ti = std::make_shared<lt::torrent_info>(torrentFilePath); //通過種子文件 定義 torrent_info對象
lt::add_torrent_params p; 
p.ti = ti;										//這兒很重要, 必須要中torrent_info對象傳遞進來
p.save_path = ".";
p.userdata = static_cast<void*>(new std::string(torrentFilePath)); //這根據自己需要而定具體數據
ses.async_add_torrent(std::move(p)); //這兒是異步調用, 調完就離開,獲取不到 session_handle

以上為 通過磁力鏈接 和 torrent 種子這兩種方式添加到session的簡單例子。torrent_info類又諸多構造函數,對象定義方法也因此非常多,根據需要選擇合適的。

另外添加種子到session的方法有 同步調用(阻塞耗時)和異步調用(立即返回)兩種,也根據需要選擇。

2. 警報

直接上代碼講解

for (;;) {
      std::vector<lt::alert*> alerts;
      ses.pop_alerts(&alerts);     //獲取自上次調用以來的新警報列表

      for (lt::alert const* a : alerts) {  //遍歷處理自己需要的警報。
          std::cout << a->message() << std::endl; 		//打印警報信息
          
         // 下面是針對各種類型的警報進行處理例子
          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;

我們可以用‘警報掩碼’抓取我們關心的警報(有很多種類),如下 :

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);

「P2P」 - libTorrent簡單使用

警報掩碼 之 掩碼類別「P2P」 - libTorrent簡單使用

警報類型

3. 更新配置選項

session啟動後,可以通過調用 apply_settings() 更新配置,

lt::settings_pack pack;
pack.set_int(lt::settings_pack::alert_mask,lt::alert::status_notification);  
ses.apply_settings(pack);     // 更新配置 alert_mask

雖然這樣可以更新配置,但有些設置最好在啟動會話之前設置,比如 listen_interfaces,以避免出現競爭條件。如果使用默認設置啟動會話,然後立即更改它們,則仍會有一個應用默認設置的窗口。

更改設置可能會觸發偵聽套接字關閉和重新打開,並發送NAT-PMP、UPnP更新。因此,將設置更新批處理到單個調用中通常是一個好主意。

4. 獲取種子狀態

for(;;){
      ses. post_torrent_updates();   // 發送 alert::status_notification
			
  		std::this_thread::sleep_for(250);
  
      std::vector<lt::alert*> alerts;
      ses.pop_alerts(&alerts);     //獲取自上次調用以來的新警報列表

      for (lt::alert const* a : alerts) {  
          //  處理 state_update_alert
          if (state_update_alert* p = alert_cast<state_update_alert>(a)) {
            			// 包含自上次調用以來更新的種子狀態
                 std::vector<torrent_status> status = p->stauts;
            			......
          }
      }  
      ....
}

5. 恢複種子

恢復下載時,BT引擎必須恢復正在下載種子的狀態,特別是文件的哪些部分已下載, 有兩種方法可以做到這一點:

(1) 從磁盤讀取已下載文件片段,並將其與預定的哈希值進行比較。

(2) 保存已下載的片段(和部分片段)的狀態到磁盤,並在恢復時重新加載。

如果添加種子時沒有提供恢複數據,那麼libtorrent將默認使用上面第1點。

libtorrent有提供函數,實現保存恢複數據的功能:

 torrent_handle.save_resume_data(torrent_handle::save_info_dict) ; 

調用該函數的時機:

(1). 人為地選中某個種子,操作‘保存恢複數據’。

(2). 每個種子加載完成時。

(3). 關閉session之前。

注意:調用該函數並沒將恢複數據保存到磁盤上面, 調用該函數後實際上會發出警報:

save_resume_data_alert(若成功) 或
save_resume_data_failed_alert
(若失敗)

	else if (save_resume_data_alert* p = alert_cast<save_resume_data_alert>(a))
	{
		torrent_handle h = p->handle; // 獲取torrent_handle,目的是獲取torrent_status
		auto const buf = write_resume_data_buf(p->params); // p->params為 add_torrent_params 類型
		torrent_status st = h.status(torrent_handle::query_save_path);
		save_file(resume_file(st.info_hash), buf); //保存恢複數據到名為info_hash(長度40)的文件中
	}
	else if (save_resume_data_failed_alert* p = alert_cast<save_resume_data_failed_alert>(a))
	{
		// 如果不需要保存恢複數據,可以不打印錯誤信息
		return p->error == lt::errors::resume_data_not_modified;
	}

6. session對象的析構銷毀

默認情況下會話析構函數會被阻塞。關閉時,需要聯繫追蹤器以停止種子,其他未完成的操作需要取消。關閉有時可能需要幾秒鐘,主要是因為跟蹤器沒有響應(和超時)以及DNS服務器沒有響應。DNS查找在失控時尤其難以中止。

為了能夠異步地開始銷毀等待,可以調用session::abort()。它返回一個session_proxy對象,它是一個句柄,用於在銷毀會話狀態時保持會話狀態。它故意不提供任何會話操作,因為它正在關閉。

擁有session_proxy對象後,會話析構函數不會阻塞。但是session_proxy析構函數卻將被阻塞。

這可用於並行關閉多個會話或應用程序的其他部分。

7. 完整實例

#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;

//  返回 種子各種狀態的名稱
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();

  // 從磁盤加載恢複數據,並在添加磁力鏈接時傳遞它
  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) { //判斷恢複數據和磁力鏈接是否匹配,以磁力鏈接為準
    p = std::move(magnet);
  }
  p.save_path = "."; // 保存到當前目錄
  ses.async_add_torrent(std::move(p));

  lt::torrent_handle h;  //當我們收到add_torrent_alert時,我們設置它
  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準備就緒,保存到磁盤文件
      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;

        // 因為我們只有一個種子,所以我們知道 這個status是哪個種子的
        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 更新種子輸出狀態
    ses.post_torrent_updates();

    // 每30秒保存恢複數據一次
    if (clk::now() - last_save_resume > std::chrono::seconds(30)) {
      		h.save_resume_data();
      		last_save_resume = clk::now();
    }
  }

  // 理想情況下,我們應該在這裡保存恢複數據
	done:
  		std::cout << "ndone, shutting down" << std::endl;
}
catch (std::exception& e) {
     std::cerr << "Error: " << e.what() << std::endl;
}

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/274616.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-17 14:15
下一篇 2024-12-17 14:15

相關推薦

發表回復

登錄後才能評論