在网站里下载bt种子时怎么如何获取bt种子infohash

P2P中DHT网络爬虫
发表于 日 00:00 | Hits: 1971
DHT网络爬虫基于DHT网络构建了一个P2P资源搜索引擎。这个搜索引擎不但可以用于构建DHT网络中活跃的资源索引(活跃的资源意味着该网络中肯定有人至少持有该资源的部分数据),还可以分析出该网络中的热门分享资源。不久前发布了一个这样的搜索引擎:。他也写博客对此稍作了介绍:。网络上其实也有其他人做了类似的应用:,
但是他的这篇文章仅介绍了DHT网络的大致工作原理,并且这个爬虫的具体工作原理也没有提到。对此我查阅了些文章及代码,虽然从原理上梳理出了整个实现方案,但很多细节还是不甚清楚。所以本文仅作概要介绍。
DHT/Magnet/Torrent
在P2P网络中,要通过种子文件下载一个资源,需要知道整个P2P网络中有哪些计算机正在下载/上传该资源。这里将这些提供某个资源下载的计算机定义为peer。传统的P2P网络中,存在一些tracker服务器,这些服务器的作用主要用于跟踪某个资源有哪些关联的peer。下载这个资源当然得首先取得这些peer。
DHT的出现用于解决当tracker服务器不可用时,P2P客户端依然可以取得某个资源的peer。DHT解决这个问题,是因为它将原来tracker上的资源peer信息分散到了整个网络中。这里将实现了DHT协议的计算机定义为节点(node)。通常一个P2P客户端程序既是peer也是节点。DHT网络有多种实现算法,例如Kademlia。
当某个P2P客户端通过种子文件下载资源时,如果没有tracker服务器,它就会向DHT网络查询这个资源对应的peer列表。资源的标识在DHT网络中称为infohash,是一个20字节长的字符串,一般通过sha1算法获得,也就是一个类似UUID的东西。
实际上,种子文件本身就对应着一个infohash,这个infohash是通过种子文件的文件描述信息动态计算得到。一个种子文件包含了对应资源的描述信息,例如文件名、文件大小等。Magnet,这里指的是磁力链接,它是一个类似URL的字符串地址。P2P软件通过磁力链接,会下载到一个种子文件,然后根据该种子文件继续真实资源的下载。
磁力链接中包含的最重要的信息就是infohash。这个infohash一般为40字节或32字节,它其实只是资源infohash(20字节)的一种编码形式。
Kademlia是DHT网络的一种实现。网络上关于这个算法的文章,主要是围绕整个DHT网络的实现原理进行论述。个人觉得这些文章很蛋疼,基本上读了之后对于要如何去实现一个DHT客户端还是没有概念。这里主要可参考,以及BitTorrent网站上的
Kad的主要目的是用于查询某个资源对应的peer列表,而这个peer列表实际上是分散在整个网络中。网络中节点数量很大,如果要获得peer列表,最简单的做法无非就是依次询问网络中的每个节点。这当然不可行。所以在Kad算法中,设立了一个路由表。每一个节点都有一份路由表。这个是按照节点之间的距离关系构建出来的。节点之间的距离当然也有特定的算法定义,在Kad中通过对两个节点的ID进行异或操作得到。节点的ID和infohash通过相同算法构建,都是20字节长度。节点和infohash之间也有距离关系,实际上表示的是节点和资源的距离关系。
有了这个路由表之后,再通过一个基于距离关系的查找算法,就可以实现不用挨个遍历就找到特定的节点。而查找资源peer这个操作,正是基于节点查找这个过程。
路由表的实现,按我的理解,有点类似一般的hash表结构。在这个表中有160个桶,称为K桶,这个桶的数量在实现上可以动态增长。每个桶保存有限个元素,例如K取值为8,指的就是这个桶最多保存8个元素。每个元素就是一个节点,节点包含节点ID、地址信息以及peer信息。这些桶可以通过距离值索引得到,即距离值会经过一个hash算法,使其值落到桶的索引范围内。
要加入一个DHT网络,需要首先知道这个网络中的任意一个节点。如何获得这个节点?在一些开源的P2P软件中,会提供一些节点地址,例如中提供的:6881。
Kad定义了节点之间的交互协议。这些协议支撑了整个DHT网络里信息分布式存储的实现。这些协议都是使用UDP来传送。其协议格式使用一种称为的编码方式来编码协议数据。bencode是一种文本格式的编码,它还用于种子文件内的信息编码。
Kad协议具体格式可参考BitTorrent的定义:。这些协议包括4种请求:ping,find_node,get_peer,announce_peer。在有些文档中这些请求的名字会有不同,例如announce_peer又被称为store,get_peer被称为find_value。这4种请求中,都会有对应的回应消息。其中最重要的消息是get_peer,其目的在于在网络中查找某个资源对应的peer列表。
值得一提的是,所有这些请求,包括各种回应,都可以用于处理该消息的节点构建路由表。因为路由表本质就是存储网络中的节点信息。
用于确定某个节点是否在线。这个请求主要用于辅助路由表的更新。
用于查找某个节点,以获得其地址信息。当某个节点接收到该请求后,如果目标节点不在自己的路由表里,那么就返回离目标节点较近的K个节点。这个消息可用于节点启动时构建路由表。通过find_node方式构建路由表,其实现方式为向DHT网络查询自己。那么,接收该查询的节点就会一直返回其他节点了列表,查询者递归查询,直到无法查询为止。那么,什么时候无法继续查询呢?这一点我也不太清楚。每一次查询得到的都是离目标节点更接近的节点集,那么理论上经过若干次递归查询后,就无法找到离目标节点更近的节点了,因为最近的节点是自己,但自己还未完全加入网络。这意味着最后所有节点都会返回空的节点集合,这样就算查询结束?
实际上,通过find_node来构建路由表,以及顺带加入DHT网络,这种方式什么时候停止在我看来并不重要。路由表的构建并不需要在启动时构建完成,在以后与其他节点的交互过程中,路由表本身就会慢慢地得到构建。在初始阶段尽可能地通过find_node去与其他节点交互,最大的好处无非就是尽早地让网络中的其他节点认识自己。
通过资源的infohash获得资源对应的peer列表。当查询者获得资源的peer列表后,它就可以通过这些peer进行资源下载了。收到该请求的节点会在自己的路由表中查找该infohash,如果有收录,就返回对应的peer列表。如果没有,则返回离该infohash较近的若干个节点。查询者若收到的是节点列表,那么就会递归查找。这个过程同find_node一样。
值得注意的是,get_peer的回应消息里会携带一个token,该token会用于稍后的announce_peer请求。
announce_peer
该请求主要目的在于通知,通知其他节点自己开始下载某个资源。这个消息用于构建网络中资源的peer列表。当一个已经加入DHT网络的P2P客户端通过种子文件开始下载资源时,首先在网络中查询该资源的peer列表,这个过程通过get_peer完成。当某个节点从get_peer返回peer时,查询者开始下载,然后通过announce_peer告诉返回这个peer的节点。
announce_peer中会携带get_peer回应消息里的token。关于这一点,我有一个疑问是,在文档中提到:
(announce_peer)同时会把自己的peer信息发送给先前的告诉者和自己K桶中的k个最近的节点存储该peer-list信息
不管这里提到的K的最近的节点是离自己最近,还是离资源infohash最近的节点,因为处理announce_peer消息时,有一个token的验证过程。但是这K个节点中,并没有在之前创建对应的token。我通过transmission中的DHT实现做了个数据收集,可以证明的是,announce_peer消息是不仅仅会发给get_peer的回应者的。
DHT爬虫是一个遵循Kad协议的假节点程序。具体可以参考小虾发布的那个网站应用:。
这个爬虫的实现方式,主要包含以下内容:
通过其他节点的announce_peer发来的infohash确认网络中有某个资源可被下载
通过从网络中获取这个资源的种子文件,来获得该资源的描述
通过累计收集得到的资源信息,就可以提供一个资源搜索引擎,或者构建资源统计信息。以下进一步描述实现细节。整个爬虫的实现依赖了一个很重要的信息,那就是资源的infohash实际上就是一个磁力链接(当然需要包装一下数据)。这意味着一旦我们获得了一个infohash,我们就等于获得了一个种子。
获得资源通知
当爬虫程序加入DHT网络后,它总会收到其他节点发来的announce_peer消息。announce_peer消息与get_peer消息里都带了资源的infohash,但是get_peer里的infohash对应的资源在该网络中不一定存在,即该资源没有任何可用peer。而announce_peer则表示已经确认了该网络中有节点正在下载该资源,也即该资源的数据确实存在该网络中。
所以,爬虫程序需要尽最大努力地获取其他节点发来的announce_peer消息。如果announce_peer消息会发送给离消息发送节点较近的节点,那么,一方面,爬虫程序应该将自己告诉网络中尽可能多的节点。这可以通过一次完整的find_node操作实现。另一方面,爬虫程序内部实现可以部署多个DHT节点,总之目的在于尽可能地让爬虫程序称为其他节点的较近者。
当收集到infohash之后,爬虫程序还需要通过该infohash获得对应资源的描述信息。
获取资源信息
获得资源描述信息,其实就是通过infohash获得对应的种子文件。这需要实现P2P协议里的文件分享协议。种子文件的获取其实就是一个文件下载过程,下载到种子文件之后,就可以获取到资源描述。这个过程一种简单的方法,就是从infohash构建出一个磁力链接,然后交给一个支持磁力下载的程序下载种子。
从infohash构建出磁力链接非常简单,只需要将infohash编码成磁力链接的xt字段即可,构建实现可以从transmission源码里找到:
/* 这个算法其实和printf(&%02x&, sha1[i])一样 */
void tr_sha1_to_hex (char *out, const unsigned char *sha1)
static const char hex[] = &abcdef&;
for (i=0; i&20; ++i) {
const unsigned int val = *sha1++;
*out++ = hex[val && 4];
*out++ = hex[val & 0xf];
*out = '\0';
void appendMagnet(FILE *fp, const unsigned char *info_hash) {
char out[48];
tr_sha1_to_hex(out, info_hash);
fprintf(fp, &magnet:?xt=urn:btih:%s&, out);
现在你就可以做一个实验,在transmission的DHT实现中,在announce_peer消息的处理代码中,将收到的infohash通过上面的appendMagnet转换为磁力链接输出到日志文件里。然后,可以通过支持磁力链接的程序(例如QQ旋风)直接下载。有趣的是,当QQ旋风开始下载该磁力链接对应的种子文件时,你自己的测试程序能收到QQ旋风程序发出的announce_peer消息。当然,你得想办法让这个测试程序尽可能地让其他节点知道你,这可以通过很多方式实现。
最终的DHT爬虫除了需要实现DHT协议之外,还需要实现P2P文件下载协议,甚至包括一个种子文件解析模块。看起来包含不小的工作量。而如果要包装为一个资源搜索引擎,还会涉及到资源存储以及搜索,更别说前端呈现了。这个时候,如果你使用的语言不包含这些工具库,那实在是太悲剧了。没错,我就没找到一个erlang DHT库(倒是有erlang实现的BT客户端,懒得去剥了)。
原文地址:
written by posted at
评价列表(0)程序和代码下载:
最新,包含 x64 版本:
或者在这里找:
Hash 值为 004ff128d528d0773fdefbc298cce 的种子,可以通过以下链接下载:
  产生这个 URL 的关键是 key 的计算,上例中 key=44a2a4cf54ccba26730。UMU 做了一个 COM 对象,实现了 Hash 到 Key 的计算。
下面是脚本代码:
Dim objUMU
Dim strHash
Dim strURL
Set objUMU = CreateObject("UMU.UrlGenerator")
strHash = InputBox("请输入 torrent 种子散列值:", "输入 Hash 值", "004ff128d528d0773fdefbc298cce") If Len(strHash) && 40 Then
&&&&&&& WScript.Quit
strURL = "=" & strHash & "&size=&key=" & objUMU.GenBitCometTorrentKey(strHash)
Set objUMU = Nothing
If Not IsEmpty(InputBox("生成的 URL 如下,按&确定&打开链接。", "结果", strURL)) Then
&&&&&&& Dim objWSH
&&&&&&& Set objWSH = CreateObject("Wscript.Shell")
&&&&&&& objWSH.Run strURL
&&&&&&& Set objWSH = Nothing
  增加 info_hash 转化成磁力链接(magnet)的功能,如果上面的方法下不到种子,可以试试这种,获得链接后用迅雷下载:
Dim objUMU
Dim strHash
Dim strURL
Set objUMU = CreateObject("UMU.UrlGenerator")
strHash = InputBox("请输入 torrent 种子散列值:", "输入 Hash 值", "77fd3c6ca0e9bc72e4") If Len(strHash) && 40 Then
&&&&&&& WScript.Quit
strURL = "magnet:?xt=urn:btih:" & objUMU.TorrentHashToMagnetUri(strHash)
Set objUMU = Nothing
If Not IsEmpty(InputBox("生成的 URL 如下,按&确定&打开磁力链接。", "结果", strURL)) Then
&&&&&&& Dim objWSH
&&&&&&& Set objWSH = CreateObject("Wscript.Shell")
&&&&&&& objWSH.Run strURL
&&&&&&& Set objWSH = Nothing
最新研究表明,直接在 info_hash 加上前缀 magnet:?xt=urn:btih: 就可以用迅雷下载了。
阅读(...) 评论() &博客访问: 1441315
博文数量: 266
博客积分: 1305
博客等级: 军士长
技术积分: 4661
注册时间:
不懂的东西还有很多,随着不断的学习,不懂的东西更多,无法消灭更多不懂的东西,那就不断的充实自己吧。
欢迎关注微信公众号:菜鸟的机器学习
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: 网络与安全
&&&&& BTDHTBTBT& 小弟我最近正在研究BT通信协议,网上的资料很全,但是不是那事详细和完整,因此,整理下来,一方面他日用到拿来看看,另一方面,希望对正在研究BT通信协议的有点帮助。若有不正之处,请指正。
&&&&&& BT3.torrenttracker HTTP/HTTPSpeer wire(TCP)tracker
HTTP/HTTPSBTtrackerpeer wireBT
1.1 torrent
&&&&&& .torrentBB4bytestringsintegerslistsdictionariesintegerslistsdictionariesildebytestrings/&&&&4:spam“spam”4.torrent
d8:announce39::80/announce13:announce-listll39::80/announceel32::2710/announceel44:udp://:80/announceel42:http://tracker.torrentbay.to:6969/announceel39:http://tracker.torrent.to:2710/announceel27::80/announceel28:/announceel38::6969/announceel42:http://tracker.novalayer.org:6969/announceel35:udp://tracker.1337x.org:80/announceee
●announcetrackerURLhttp//xp.com:8080/announce
●announce-listtrackerURLxp.com:8080/announce,http://btfans.3322.org:6969/announce
●creationdate.torrentUNIX
●comment.torrent
●createdby.torrentBitComet/0.67
●encodingGBK
&●infolengthmd5sumnamepiecelengthpiecesfilesnamepiecelengthpiecesfileslengthpathmd5sumlengthpathmd5sum
1.2 tracker HTTP/HTTPS
&&&&&& BT.torrenttrackerrtracker
TrackerIP DNS
DNSTrackerIP
&&&&&& 95.211.88.5495.211.88.4995.211.88.51
& & & &&&&&&& & &&&&&&&&&& 83.149.126.97
& & & & & & & && & & & & & & 208.83.20.164
& & & & & & & &&&&&&&&&& & &&&&&&&&&&
& & & & & & & &tracker.novalayer.org& & & & & 194.54.80.150
& & & & & & & && & & & & &95.211.88.5495.211.88.4995.211.88.51
& & & &tracker.torrent.to& & & & & & &127.0.0.1
& & & & & & & &tracker.torrentbay.to&&&&&&&&& 109.235.55.11
& & & & & & & &tracker.1337x.org: & & & & & & & 95.215.62.224
& & & & & & & &: 95.215.62.26
&&&&&& TrackerIP
TrackerHTTP/HTTPS
&&&&&& BT.torrenttrackerpeersIPtracker
BTTrackerHTTP
&&&&&& 447号分组中的HTTP部分内容如图6所示。
●info_hash.torrentinfosha120Tracker
●peer_idBT20bitpeer-id
●port10775
●uploaded/downloaded/Tracker”started”
●numwantTracker
●key:IPBT
●compact16byte4byteIP2byte0
&&&&&& Tracker
&&&&&& Trackertrackerinfo_hashNatCheckIPIP
&&&&&& 660ASCII66016peers76peers10peers34interval1967BT1967tracker983peer660BT6110
&1.3 peer wire
&&&&&& BT208.131.161.209:53062TCPA208.131.161.209:53062B172.16.8.93:3012.
&&&&&& TCP
(1)Handshake
(2)BitfieldBAA283
(3)interestednointerestedchokeunchoke4
(4)request piecepiece
(5)peer wireTCPABTCP
&&&&&& Handshake&pstrlen&&pstr&&reserved&&info_hash&&peer_id&
&&&&&& pstrlen:
& & & & & &pstr:
& & & & & &reserved: 8 0.Bram
& & & & & info_hash: info (key)20 SHA1
nfo_hashtracker & & & & & & & & & & &info_hash
& & & & & peer_id: 20 peer_id tracker peer_id(Azureus)
&&&&&& BitTorrent 1.0
pstrlen = 19, pstr = BitTorrent protocol
&&&&&& torrent(torrent infohash )info_hash tracker NAT-checking peer_id
&&&&&& info_hashpeer_id peer_id tracker peer
peer peer_idtracker
peer_id peer_id
&&&&&& bitfield:
&len=0001+X&&id=5&&bitfield&
&&&&&& itfield piece()bitfield x bitfield
payload bitfieldbitfield
piece()piece 00
piece1 piece0
& & & &长bitfield
bitfield bitfield
&request piece
&&&&&& request piece
&&&&&& payload
&&&&&& indexpiece
&&&&&& beginpiece
&&&&&& length
阅读(12640) | 评论(12) | 转发(2) |
相关热门文章
给主人留下些什么吧!~~
:感觉可能是我的请求的infohash有问题。。想问一下,tracker的get请求的infohash的值,是否是经过sha1后,然后在经过http编码后的值??急求啊,楼主。。
infohash是从种子文件中获取的,,, |
为什么我发送完数据请求后,对方peer没有回应呢?已经确认过了,发送的请求包没有问题//
:文章写得真的不错,每一步都有具体数据对应讲解,帮助真的很大,看完有意犹未尽的感觉,谢谢!!!
谢谢&一起交流 |
:感觉可能是我的请求的infohash有问题。。想问一下,tracker的get请求的infohash的值,是否是经过sha1后,然后在经过http编码后的值??急求啊,楼主。。
每个种子文件中都有其相应的infohash,那么你根据种子文件就可以解析出来infohash,然后构造&HTTP&Get数据报就可以了,用wireshark抓包,看看包是怎么构造的,我记得不需要自己编码 |
:不好意思,好久没来了,哪里不清楚,互相交流下。
感觉可能是我的请求的infohash有问题。。想问一下,tracker的get请求的infohash的值,是否是经过sha1后,然后在经过http编码后的值??急求啊,楼主。。 |
请登录后评论。DHT抓取程序开源地址:
数据处理程序开源地址:
DHT系列文章:
--------------------------------------------------------------------------------------------------------------------
看懂此文章需要提前看明白上面的系列文章,还需要你有TCP网络编程和bencode编码方法基础上,如果都看不明白,可以到娱乐区&&去看看,休息下...
在介绍了这么多期文章后,最后介绍BT网络里面一个比较重要种子下载协议,方便大家知道如何从DHT网络直接下载种子的问题.
先说下我们目前下载电影等文件是如何下载的,比如我们有个BT种子,就可以去下载对应的文件,但如果我们只有个文件名字,如何去找BT种子呢?
首先我们可以去&去通过搜索得到磁连接,然后就由此字符串去下载对应的种子文件和电影等信息,但如果没有网站让你下载种子,我们又当如何去搜索这个种子呢?
目前我们下载BT种子有两种方式: & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
通过HTTP直接从WEB服务器上下载,这种直接方便,比如从迅雷服务器上下载种子,
再就是通过BT软件从网络里面去获取BT网络里面专门有个下载种子的协议文件,只能下载种子,然后种子下载好后就可以交给BT软件来下载数据了.
如何从DHT网络下载种子,必须先看两个协议文章:
这里面有介绍,但还是需要说明一下如何操作的流程方便大家更好的理解.
&我们的代码流程必须还是基于&DHT抓取程序开源地址:&之上,因为是从DHT网络里面获取数据,
需要我们在此之上操作后续流程.
之前的DHT有SEARCH的相关代码来搜索这个HASH对应的哪些IP在提供下载.
/* This is how you trigger a search for a torrent hash.
If port (the second argument) is non-zero, it also performs an announce.
Since peers expire announced data after 30 minutes, it's a good idea to reannounce every 28 minutes or so. */
if(searching) {
//m_dht.dht_random_bytes((void*)hashList[2],20);
if(m_soListen &= 0)
m_dht.dht_search(hashList[2], 0, AF_INET, DHT_callback, this);
if(s6 &= 0)
m_dht.dht_search(hashList[2], 0, AF_INET6, DHT_callback, this);
searching = 0;
搜索到对方返回的IP信息和端口号后,大家可以分析dht.c里面的函数代码dht_periodic(const void *buf, size_t buflen,const struct sockaddr *fromAddr, int fromlen,time_t *tosleep,dht_callback *callback, void *closure)函数里面的ANNOUNCE_PEER返回请求里面带有对方表明自己此BT种子对应的认证码peerid.
dht_periodic(const void *buf, size_t buflen,const struct sockaddr *fromAddr, int fromlen,time_t *tosleep,dht_callback *callback, void *closure)
函数里面的ANNOUNCE_PEER
case ANNOUNCE_PEER:
_dout("Announce peer!From IP:%s:%d\n",inet_ntoa(tempip-&sin_addr),tempip-&sin_port);
new_node(id, fromAddr, fromlen, 1);
if(id_cmp(info_hash, zeroes) == 0)
_dout("Announce_peer with no info_hash.\n");
send_error(fromAddr, fromlen, tid, tid_len,203, "Announce_peer with no info_hash");
if(!token_match(token, token_len, fromAddr)) {
_dout("Incorrect token for announce_peer.\n");
send_error(fromAddr, fromlen, tid, tid_len,203, "Announce_peer with wrong token");
if(port == 0) {
_dout("Announce_peer with forbidden port %d.\n", port);
send_error(fromAddr, fromlen, tid, tid_len,203, "Announce_peer with forbidden port number");
if(callback)
(*callback)(closure, DHT_EVENT_ANNOUNCE_PEER_VALUES, info_hash,(void *)fromAddr, port,id);//此ID就是peerid,
知道了对应的IP,端口号,还有种子ID号,就可以向对方发送请求了.
获取HASH是通过UDP网络,但下载BT种子是通过TCP来处理,相当于别人是TCP服务器,我们连接过去,直接下载对应PEERID的种子就行了.
BT种子在DHT网络下载流程 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
&先看http://www.bittorrent.org/beps/bep_0010.html协议介绍,我们必须先握手 &
&此包构造比较简单,按照格式进行组装就行了,然后发送出去,对方就会回应自己是什么客户端的软件提供种子下载.
void CH31BTMgr::Encode_handshake()
//a byte with value 19 (the length of the string that follows);
//the UTF-8 string "BitTorrent protocol" (which is the same as in ASCII);
//eight reserved bytes use
//the 20 bytes of t
//the 20 bytes of the peer ID.
char btname[256];
memset(btname,0,sizeof(btname));
sprintf(btname,"BitTorrent protocol");
char msg[1280];
memset(msg,0,sizeof(msg));
msg[0]=19;
memcpy(&msg[1],btname,19);
char ext[8];
memset(ext,0,sizeof(ext));
ext[5]=0x10;
memcpy(&msg[20],ext,8);
memcpy(&msg[28],m_hash,20);
memcpy(&msg[48],m_peer_id,20);
int res1=Write(msg, 68);//TCP发送消息
在发送握手后,我们可以接着发送种子数据请求包,需要学习http://www.bittorrent.org/beps/bep_0009.html 里面的内容:  
extension header
The metadata extension uses the extension protocol (specified in BEP 0010 ) to advertize its existence. It adds the "ut_metadata" entry to the "m" dictionary in the extension header hand-shake message. This identifies the message code used for this message. It also adds "metadata_size" to the handshake message (not the "m" dictionary) specifying an integer value of the number of bytes of the metadata.
Example extension handshake message:
{'m': {'ut_metadata', 3}, 'metadata_size': 31235}
extension message
The extension messages are bencoded. There are 3 different kinds of messages:
The bencoded messages have a key "msg_type" which value is an integer corresponding to the type of message. They also have a key "piece", which indicates which part of the metadata this message refers to.
In order to support future extensability, an unrecognized message ID MUST be ignored.
这就需要会bencode的相关代码,这个大家可以网上搜索进行编译,如果实现搞不定,可以留下邮箱我将此类代码发送给你,其实也是网上收集整理的.
void CH31BTMgr::Encode_Ext_handshake()
m["ut_metadata"] = 0;
char msg[200];
char* header =
char* p = &msg[6];
int len = bencode(p, e);
int total_size = 2 +
namespace io =
io::write_uint32(total_size, header);
io::write_uint8(20, header);
io::write_uint8(0, header);
int res1=Write(msg, len + 6);
如果别人回应的是2,那就直接退出吧,说明别人拒绝了你.
如果回应是1,则返回的是数据区,每块是16K大小,最后一包不是.
The data message adds another entry to the dictionary, "total_size". This key has the same semantics as the "metadata_size" in the extension header. This is an integer.
The metadata piece is appended to the bencoded dictionary, it is not a part of the dictionary, but it is a part of the message (the length prefix MUST include it).
If the piece is the last piece of the metadata, it may be less than 16kiB. If it is not the last piece of the metadata, it MUST be 16kiB.
{'msg_type': 1, 'piece': 0, 'total_size': 3425}
d8:msg_typei1e5:piecei0e10:total_sizei34256eexxxxxxxx...
The x represents binary data (the metadata).
下面给出如何进行提交我需要第几包的数据代码:
void CH31BTMgr::write_metadata_packet(int type, int piece)
ASSERT(type &= 0 && type &= 2);
ASSERT(piece &= 0);
e["msg_type"] =
e["piece"] =
char const* metadata = 0;
int metadata_piece_size = 0;
if (type == 1)
e["total_size"] = 14132;
int offset = piece * 16 * 1024;
//metadata = m_tp.metadata().begin +
metadata_piece_size = (std::min)(int(14132 - offset), 16 * 1024);
char msg[200];
char* header =
char* p = &msg[6];
int len = bencode(p, e);
int total_size = 2 + len + metadata_piece_
namespace io =
io::write_uint32(total_size, header);
io::write_uint8(20, header);
io::write_uint8(m_message_index, header);
int res1=Write(msg, len + 6);
在接收到一包请求后我们才可以继续下一包的请求,下面给了我们如何解析这一包的问题代码:
// 处理一个完整的包数据
bool CH31BTMgr::DeCodeFrameData(char * buffer,int buflen)
char * p = (char *)mhFindstr(buffer, buflen, "ut_metadatai", 12);
m_message_index=atoi(&p[12]);
if(m_message_index==2)
return false;
write_metadata_packet(0,0);
char filename[256];
memset(filename,0,sizeof(filename));
sprintf(filename,"%s\\torrent.txt",m_workPath);
DelFile(filename);
p = (char *)mhFindstr(buffer, buflen, "metadata_sizei", 14);
m_metadata_size=atoi(&p[14]);
m_fileCnt=(int)(m_metadata_size/16384)+1;
p = (char *)mhFindstr(buffer, buflen, "msg_typei", 9);
int type1=atoi(&p[9]);
if(type1==1)
p = (char *)mhFindstr(buffer, buflen, "piecei", 6);
int piece=atoi(&p[6]);
p = (char *)mhFindstr(buffer, buflen, "total_sizei", 11);
int total_size=atoi(&p[11]);
p = (char *)mhFindstr(buffer, buflen, "ee", 2);
//保存数据
FILE* pfile=NULL;
char filename[256];
memset(filename,0,sizeof(filename));
sprintf(filename,"%s\\torrent.txt",m_workPath);
char openmethod[5]="a";
if(piece==0)
sprintf(openmethod,"w");
if((pfile=fopen(filename,openmethod))!=NULL)
if((piece+1)*16*1024&total_size)
fseek(pfile,(piece)*16*1024,SEEK_SET);
fwrite(&p[2],1,16*1024,pfile);
write_metadata_packet(0,piece+1);
fclose(pfile);
fwrite(&p[2],1,total_size-(piece)*16*1024,pfile);
fclose(pfile);
ManageTorrentFileToRealFile(filename);
else if(type1==2)
return false;
return true;
void * mhFindstr(const void *haystack, size_t haystacklen,const void *needle, size_t needlelen){ const char *h =(const char *) const char *n =(const char *) size_
/* size_t is unsigned */ if(needlelen & haystacklen)
return NULL;
for(i = 0; i &= haystacklen - i++) {
if(memcmp(h + i, n, needlelen) == 0)
return (void*)(h + i); } return NULL;}
接下来说下如何进行快速调试的问题: & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
& & & &第一次调试也很天真的等着DHT网络上的数据过来,需要等很久,而且调试总是发现别人不回应,要么就是拒绝,经过一段时间后,
问朋友总是不对问题,结果是协议没有构造对.下面就需要注意的地方总结下:
1.一定要接收到别的人PEERID后才能够与别人交流,不然别人肯定不理你;
2.构造协议调试不能够在外网络上调试,最好大家将mono-monotorrent源代码下载回来,调试分析下,本地开启服务器;
3.通过本地与mono-monotorrent进行调试,你就可以分析出是哪里不对的问题,是不是协议哪些封装得不对的问题.
4.通过DHT网络下载回来的种子肯定是最新的,WEB下载的可能还没有呢..
5.通过协议下载回来的种子好像没有announce-list,不知道为什么不提供一些内容,可能还有些什么关键地方没有下载,分析mono-monotorrent代码里面就是不提供下载,希望高手指点.
6.TCPClient接收数据区需要开到16K以上,这样方便处理,当然如果会前后拼接包就更好.
7.如果需要bencode相关的编码C++代码,可以在此留言或者给发邮件.
如果此文章看不太明白,请先看看之前的文章,分析调试下代码,再来学习此文章可能就比较懂一些.
希望有了解的朋友更好的交流和进步.在此留言学习讨论.
大家看累了,就移步到娱乐区&去看看,休息下...
希望大家多多推荐哦...大家的推荐才是下一篇介绍的动力...
阅读(...) 评论()

我要回帖

更多关于 虐杀12小时bt种子下载 的文章

 

随机推荐