第一章的目的是大致了解libed2k怎么使用,libed2k库自带了一个测试工程conn,这一章我们将分析conn,让从我们最关心的下载文件开始。

1.1 解析ed2k链接

通常在网上分享的电驴资源时都是通过ed2k链接的方式,ED2K链接格式为:

ed2k://|file|cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso|3420557312|B58548681854236C7939003B583A8078|h=TQXCJQ2QAYCXKMFQKKHRZJ4WE34T3TDA|/

解析链接的代码在libed2k\include\libed2k\file.hpp中:

static emule_collection_entry fromLink(const std::string& strLink);

它的实现如下:

(1)读取0-13字节并检查是否为“ed2k://|file|”

(2)读取从13字节开始到下一个“|”,得到文件名。

(3)读取从文件名之后到下一个“|”的位置,得到文件大小

(4)读取从文件大小之后到下一个“|”的位置,得到hash值。

(5)丢弃剩余部分“h=TQXCJQ2QAYCXKMFQKKHRZJ4WE34T3TDA”

得到文件名,大小和哈希值后存放到结构体emule_collection_entry中。这个结构体内的成员与这些值一一对应。直接用if(emule_collection_entry)函数可以判断是否是有意义的一个结构体(重载了bool ()操作符)。

1.2 emule任务清单

emule文件集合类(叫做emule任务清单或许更恰当)emule_collection封装了std::deque<emule_collection_entry>并提供了一些额外的操作。

静态函数:

(1)提供从“ed2k://”链接到emule_collection_entry的转换的fromLink方法(见1.1)。

(2)提供从文件名,文件大小和哈希值生成“ed2k://”链接的toLink方法。

(3)从磁盘文件中读取任务清单的fromFile方法。

成员函数:

(1)保存任务清单到文件的save方法。

(2)添加文件到任务清单的add_file方法(需要文件名,文件大小和哈希值)。

(3)添加“ed2k://”链接到任务清单的add_link方法。

(4)从任务清单中根据序号(index)获取emule_collection_entry元素并生成“ed2k://”链接的get_ed2k_link方法。

(5)重载的==操作符,用于对比两个emule_collection是否相同

成员变量:

(1)emule_collection_entry集合

(2)集合名字(string name;),这个值保留未用

1.3 添加链接并下载

参照qtlibed2k\qed2ksession.cpp的QPair<Transfer,ErrorCode> QED2KSession::addLink(QString strLink, bool resumed /* = false */),在conn工程中添加一个命令download_addlink。

case cc_download_addlink:
{ DBG("Add link and download: " << strArg); libed2k::emule_collection_entry ece = libed2k::emule_collection::fromLink(strArg); if (!ece) { DBG("Incorrect link"); } else { DBG("Link is corrent, add transfer."); libed2k::add_transfer_params atp; atp.file_hash = ece.m_filehash; boost::filesystem::path p(strIncomingDirectory); p.append(ece.m_filename); atp.file_path = p.string(); atp.file_size = ece.m_filesize; atp.duplicate_is_error = true; atp.dump(); libed2k::transfer_handle h = ses.add_transfer(atp); //We usually need to save the     transfer handler to get information or abort the transfer mission. //As a simple example we just ignore it here. } break;
}

测试:conn 176.103.48.36 4184 D:\123,然后在连接上服务器后使用新增的download_addlink命令:

download_addlink:ed2k://|file|xxxx.mp4|574013397|039FDC9AD3CDC79E952540BD3ACE5982|/

结果如下图:

可以看到大部分的显示内容不是我们要的,我关心的是连接到谁,从它们那里下载和上传到它们的速度怎么样。下载进度信息等。

1.4 libed2k的日志系统

日志系统的初始化是通过LOGGER_INIT(x)宏控制,这个宏参数的意义是日志功能,定义如下:

const unsigned char LOG_CONSOLE = 1; const unsigned char LOG_FILE = 2; const unsigned char LOG_ALL = '\xFF';

这三个选项的意思按其字面意思分别是将日志输出到控制台、文件或者同时写入这两者。

libed2k使用的是boost::logger(libed2k\src\log.cpp),在这里我们需要将上文中的dbg全部屏蔽可以设置过滤器的级别为info:

#include <boost/logging/format.hpp> //... void init_logs(unsigned char log_destination /*= LC_ALL*/) { //... g_l_filter()->set_enabled(level::info); }

可选的level包括:

enum { disable_all = (type)-1, enable_all = 0, debug = 1000, info = 2000, warning = 3000, error = 4000, fatal = 5000
};

具体BOOST日志库的使用方法可以阅读boost库的官方文档。

重试1.3添加ed2k链接的步骤,现在的输出是这样:

可以见到原来输出的一大堆dbg信息已经不见了。但是由于输出日志大部分是level::debug这个级别,消息过滤导致我们想看的信息也一并消失了,为保证conn里正常的信息输出我们可以将conn.cpp里的DBG全部替换成APP宏(APP对应info等级)。

接下来我们将研究alert事件通知,然后将我们关心的通知信息从level::debug改为level::info级别。

1.5 消息过滤

书接上文,在往libed2k的任务队列中插入一个“ed2k://”链接后,程序开始了从搜索peer到下载文件的过程。在这过程中输出了海量的信息,而且大部分都不是我们关心的。现在我希望能过滤它,只获取速度和下载源等几项信息。

libed2k采用了和libtorrent相同的异步消息通知方式,程序在完成一项操作后发送响应的alert类型对象到alert队列(alert_manager::post_alert_should/post_alert)。libed2k的使用者可以使用libed2k::session的set_alert_mask方法设定需要接收的alert类型。在conn项目中set_alert_mask的参数被设置为alert::all_categories(接收所有类型的alert),这也是为什么上例中会有输出大量信息的原因。

在conn项目中,接收和处理(这里仅打印输出)alert的函数是通过一个boost定时器完成,该定时器被设置为三秒后获取一次alert列表,代码如下:

boost::asio::deadline_timer alerts_timer(io, boost::posix_time::seconds(3));
//...
alerts_timer.async_wait(boost::bind(alerts_reader, boost::asio::placeholders::error, &alerts_timer, &ses));

alerts_timer三秒后调用一次alerts_reader(error_code, &alerts_timer, &ses),其中的error_code参数由boost::asio::deadline_timer负责传递,有关error_code的意义,见以下链接https://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/reference/basic_deadline_timer/async_wait.html。另外需要注意的是在没有发生错误时alerts_reader内部会再次调用alerts_timer.async_wait以达到重复触发定时器每隔三秒执行一次alerts_reader的目的。

1.6 conn程序框架分析

在继续深入学习libed2k之前,需要对conn这个测试程序的运行机制做一些了解以便在需要的时候修改一些代码验证我们的想法。

conn程序非常小源码只有不到一千行,非常小巧但是具有大部分我们下载文件所需要的功能。

由以下几个函数组成:

  1. int main(int argc, char* argv[])
  2. CONN_CMD extract_cmd(const std::string& strCMD, std::string& strArg)
  3. void alerts_reader(const boost::system::error_code& ec, boost::asio::deadline_timer* pt, libed2k::session* ps)
  4. void save_fast_resume(const boost::system::error_code& ec, boost::asio::deadline_timer* pt, libed2k::session* ps)

其中在main函数中主要做了以下几件事:

  1. 初始化日志模块
  2. 从输入参数argv中依次解析“服务器地址”,“服务器端口”和“本地硬盘文件目录”
  3. 创建、修改会话配置
  4. 以配置为参数创建会话
  5. 创建从session获取alert事件的定时器,并将alerts_reader设为定时器回调。
  6. 创建保存断点续传信息的定时器,并将save_fast_resume设置为定时器回调。
  7. 用第二步解析的服务器IP和端口连接met服务器。
  8. 开启一个输入循环,接收用户输入的命令(以冒号分隔的命令和命令参数对)并翻译成CONN_CMD命令,然后按照命令执行对应的代码。
  9. 如用户输入了quit命令则关闭alert事件定时器和save_fast_resume定时器。
  10. 等待io service线程退出。

支持的用户命令包括以下几类:

  • 在服务器上搜索资源,包括“search”,“simplesearch”和“simplesearch”
  • 下载搜索到的资源,包括“load”,“loadall”
  • 在下载列表中移除一个任务,"remove"
  • 打印下载列表所有任务,"dump"
  • 连接和断开(程序输入参数指定的)服务器"connect",“disconnect”
  • 尝试监听本地的p2p端口,“listen”
  • 打印各下载任务的上传和下载速度,"tr"
  • 添加分享目录“share”和取消分享目录“unshare”(取消分享并未实际实现)
  • 添加分享文件和取消分享文件,“sharef”和“unsharef”(都没有实际实现)
  • 保存和载入下载列表中所有任务的断点续传信息(在当前运行目录下),“save”和“restore”
  • 在第一章中新增的从“ed2k://”链接增加下载任务的“download_addlink”

(注:在调试save时会偶发weak_ptr引起的异常,这里未深究其原因。)

libed2k源码导读:(一)从ed2k链接开始相关推荐

  1. libed2k源码导读:(五)文件读写

    第五章 文件读写 5.1 文件总览 libedk文件对象一览. transfer 代表一个传输任务,一个传输任务通常只有一个文件.原始ed2k不支持目录下载 piece_picker 分片选择器 pi ...

  2. libed2k源码导读:(三)网络IO

    目录 第三章 网络IO 3.1 数据序列化和反序列化 3.1.1 以向服务器发送数据为例 3.1.2 序列化和反序列化对象的细节 3.1.3 序列化集合类对象 3.1.4 Tag,tag_list和它 ...

  3. libed2k源码导读:(二)Session接口以及实现分析

    第二章 Session接口以及实现分析 目录 第二章 Session接口以及实现分析 2.1 获取会话状态 2.2 管理会话中所有的传输任务 2.3 管理点对点连接 2.4 管理alert 2.4.1 ...

  4. 2021年最新以太坊源码导读-p2p架构

    前面部分的内容都是源码导读,可能有的朋友没有耐心把所有代码看完.这里我采用尽可能简单的方式来介绍p2p这部分的代码究竟做了什么. 一.概念篇 p2p是peer-to-peer的缩写,以太坊网络是一个去 ...

  5. 鸿蒙源码导读-01:蓝海与红海

    本文摘录自 OHOZ 团队的 OpenHarmony 源码导读项目,在线阅读(腾讯云.Github Pages)中包含最新的内容. 鸿蒙的蓝海与红海 Arch.SoC.target 环境.源码.编译 ...

  6. 20201217网警考试题目及题目源码(百度云网盘下载链接)

    20201217网警考试题目及题目源码(百度云网盘下载链接) 解题答案视频教程请关注"极客易先生"微信公众号 链接:https://pan.baidu.com/s/1pzimgPk ...

  7. JFinal 源码导读第八天(1) Db.tx 事物

    为什么80%的码农都做不了架构师?>>>    1.接上面的事物介绍 /*** IAtom support transaction of database.* It can be i ...

  8. Spring IoC 源码导读

    源码记录:spring-framework-5.1.7-source-code-read 文章导读 Spring IoC 源码系列(一)BeanDefinition 初始化与注册 Spring IoC ...

  9. 【SemiDrive源码分析】系列文章链接汇总(全)

    注意:兄弟们,因为要换工作了,本专栏暂时先不更新了,如果后续工作也涉及芯驰平台的话,那我还会继续更新下去. 有好工作机会的兄弟,也可以私信介绍给我,可以聊聊 谢谢!!! 注意:兄弟们,因为一些其他原因 ...

最新文章

  1. Linux系统分辨率设置
  2. vue的多选框存储值操作
  3. chrome自动调节窗口大小插件_高效使用Chrome浏览器的10个技巧
  4. angular js一factory,service,provider创建服务
  5. 【译】Diving Into The Ethereum VM Part 2 — How I Learned To Start Worrying And Count The Storage Cost
  6. redis 和 数据库mysql之间的关系
  7. Maven父子结构的项目依赖使用以及打包依赖_微服务项目(maven父子级项目)怎么打包
  8. 注册表操作命令reg
  9. 数学建模——相关系数(4)——斯皮尔曼相关系数(spearman)
  10. FL Studio 20.9水果编曲软件中文汉化补丁包
  11. w5500telnet协议详解_STM32F103VCT6+W5500 telnet功能实现
  12. 全国大学生智能汽车竞赛图像采集处理上位机开源!
  13. 关于H5闪退问题--资源优化
  14. windows 安装微信内存清理
  15. 基于Multisim的buck降压斩波电路仿真
  16. H5营销有什么优势?企业需要定制开发H5吗?
  17. 我的github地址:
  18. 响铃:当AI翻译能识别“语境”,我们的“地球村”梦想就不远了
  19. 阿里的人工智能之路 与谷歌亚马逊还有多大差距
  20. h5网页url跳转微信链接,小程序外链跳转任意站技术大揭秘

热门文章

  1. 陇原战役2021 ezjaba
  2. 振弦采集模块针脚接口详细说明
  3. 【爬虫+数据可视化毕业设计:英雄联盟数据爬取及可视化分析,python爬虫可视化/数据分析/大数据/大数据屏/数据挖掘/数据爬取,程序开发-哔哩哔哩】
  4. 推荐2款在线制作简历工具,附简历大礼包
  5. 软件测试Mysql题库_软件测试面试常见数据库考题及答案
  6. c语言循环左移程序,C语言中关于循环左移和循环右移
  7. c语言初学者如何编写一个相加求和程序
  8. 修改服务器后账套不存在,管家婆辉煌零售POS软件,开单更快捷
  9. C语言处理excel
  10. 最大似然估计(MLE)和最大后验概率(MAP)