libtorrent分析

libtorrent应该是目前最完善的使用C++实现的bittorrent协议客户端开源开发库。有很多的开源bittorrent客户端都是基于这个开发库。
libtorrent本身使用了boost, sigc++这些库。 其中sigc++是libtorrent的基本框架, 所以移除sigc++的包依赖几乎不可能, 另外sigc++本身也依赖了某些库, 所以libtorrent向嵌入式方向的发展难度比较大。
libtorrent 采用的是轮询的方式实现的, 而不同于windows下开发人员动不动就多线程的方式不一样。 像rtorrent的话, 整个程序就只有一个线程, 所有的工作都在这个线程里面实现。 通过轮询得到网络事件,然后激发事件(事件的激发框架是由sigc++来实现), 在事件里面会继续处理数据的收发等。
轮询支持: epoll, kqueue, select三种方式。
对文件的读写的实现: 采用的是文件内存映射的方式实现, 所以看不到对本地磁盘的文件调用read/write 或者fread/fwrite操作。缓存的管理也是通过这种方式实现的。
由于事件/信号是程序的框架。 所以在这里大致的分析一下流程。

以官方网站上提供的一个简单的例子作为分析的参考:
while (!doShutdown) {
      FD_ZERO(&readSet);
      FD_ZERO(&writeSet);
      FD_ZERO(&errorSet);
      unsigned int maxFd = pollSelect->fdset(&readSet, &writeSet, &errorSet);
      if (curlStack.is_busy())
        maxFd = std::max(maxFd, curlStack.fdset(&readSet, &writeSet, &errorSet));
      int64_t t = std::minint64_t>(1000000, torrent::next_timeout());
      timeval timeout = { t / 1000000, t % 1000000 };
      if (select(maxFd + 1, &readSet, &writeSet, &errorSet, &timeout) == -1 &&
          errno != EINTR)
        throw std::runtime_error("Error polling.");
      if (curlStack.is_busy())
        curlStack.perform();
      // 'torrent::perform()' updates the cached time and runs any
      // scheduled tasks. We call it again to remove any task that
      // might have immediate timeout or that have timed out during
      // the call to 'pollSelect::perform(...)'.
      torrent::perform();
      pollSelect->perform(&readSet, &writeSet, &errorSet);
      torrent::perform();
    }


以上是程序的主循环了。
程序在进入循环前将建立一个CURL来读取种子的内容, 所以该种子可以来自网络的, 不一定是本地文件。
torrent::Http* curlGet = torrent::Http::call_factory();
curlGet->signal_done().connect(sigc::bind(sigc::ptr_fun(&http_done), curlGet));
进入主循环后, 当种子文件读取完毕。将激发信号 curlGet->signal_done().emit();
因为在之前已经将http_done与信号进行连接, 从而调用 http_done 函数。

在http_done里面将分析种子文件, 并调用:torrent::Download d = torrent::download_add(obj);

来为下载做准备。

与hash_check信号连接。

d.signal_hash_done(sigc::bind(sigc::ptr_fun(&hash_check_done), d));
开始hash检查 d.hash_check(false); /* 参数应该是false, 否则不支持继续下载(续传)。*/
文件hash检查完后将激发signal_hash_done信号。
所以程序会调用hash_check_done函数。
程序在hash_check_done里面启动下载(下栽前应该调用hash_check, 否则出错的)。
d.start();
现在就进入了 libtorrent 的地盘了。
在download::start里
首先 使tracker_manager进入调度队列。根据tracker的不同(包括 udp, dht, http的), 发送不同的请求。这里以 tracker_http为例。
使用curl来发送请求。 完成之后激发信号, 进入调用revceive_done()
分析返回的数据, 得到AddressList。 然后是 m_parent->receive_success(this, &l);
进入TrackerList::receive_success;
进入TrackerManager::receive_success
将tracker重新加入时间队列: priority_queue_insert(&taskScheduler, &m_taskTimeout, (cachedTime + rak::timer::from_seconds(m_control->focus_normal_interval())).round_seconds());
然后是 m_slotSuccess(l);
进入 DownloadWrapper::receive_tracker_success
进入 DownloadMain::receive_connect_peers
m_slotStartHandshake(sa, this);
进入 HandshakeManager::add_outgoing
进入 create_outgoing
进入 Handshake::initialize_outgoing
连接完毕后自动进入 Handshake::event_write
握手完毕后: HandshakeManager::receive_succeeded
最后 pcb->event_read();
从而完成一个peer的连接。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用 libtorrent4j 下载种子,您需要进行以下操作: 1. 导入 libtorrent4j 库和相关的模块,例如: ```java import com.frostwire.jlibtorrent.*; ``` 2. 创建一个 `SessionManager` 对象,并设置一些参数,例如: ```java SettingsPack settings = new SettingsPack(); settings.setInteger(SettingsPack.int_types.download_rate_limit.swigValue(), 1000); settings.setInteger(SettingsPack.int_types.upload_rate_limit.swigValue(), 1000); SessionManager s = new SessionManager(); s.applySettings(settings); s.start(); ``` 在这个例子中,我们设置了最大下载速度和上传速度为 1000 B/s,并创建了一个 `SessionManager` 对象。然后,我们使用 `applySettings` 方法将设置应用于会话管理器,并使用 `start` 方法启动会话管理器。 3. 创建一个 `TorrentHandle` 对象,并通过 `addTorrentInfo` 方法将种子添加到会话管理器中,例如: ```java String torrentFilePath = "/path/to/torrent/file"; byte[] torrentFileBytes = Files.readAllBytes(Paths.get(torrentFilePath)); TorrentInfo torrentInfo = new TorrentInfo(torrentFileBytes); TorrentHandle torrentHandle = s.getTorrents().addTorrentInfo(torrentInfo); ``` 在这个例子中,我们将种子文件读入 `byte` 数组中,并使用 `TorrentInfo` 对象解析种子文件的元数据。然后,我们使用 `addTorrentInfo` 方法将元数据添加到会话管理器中,并获得一个 `TorrentHandle` 对象,用于管理下载进程。 4. 启动下载进程,例如: ```java torrentHandle.resume(); ``` 在这个例子中,我们使用 `resume` 方法启动下载进程。 5. 等待下载完成,并关闭会话管理器,例如: ```java while (!torrentHandle.isFinished()) { System.out.println("Downloaded: " + torrentHandle.getStatus().getProgress() * 100 + "%"); Thread.sleep(1000); } s.stop(); ``` 在这个例子中,我们使用 `isFinished` 方法检查下载进程是否完成,如果没有完成,则打印下载进度,并使用 `Thread.sleep` 方法暂停 1 秒钟。一旦下载完成,我们使用 `stop` 方法关闭会话管理器。 这就是使用 libtorrent4j 下载种子的基本步骤。请注意,这只是一个简单的例子,您可能需要根据具体情况进行更多的设置和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值