BT种子与Tracker解析

   日期:2024-12-26    作者:smallvick 移动:http://mip.riyuangf.com/mobile/quote/51183.html

上一篇我们已经解析出种子的基本结构。下一个问题就是,如何通过种子文件所给的信息,获取文件的下载地址。

part1.地址格式
首先,我们可以发现,announce和announce-list里面的地址有两种格式的,udp开头的地址,以及http开头的地址。http开头的地址很好理解就是遵循http协议的地址。那udp开头的地址就是遵循udp协议的地址喽。这样理解有对也有不对。准确点讲这个udp地址实际上是遵循udp tracker 协议.(注意:上面两种地址都是无法浏览器直接访问的。)

part2.请求构造解析
1.对于http开头的地址,bt协议对其的介绍在这
http://www.bittorrent.org/beps/bep_0023.html
简单来讲,就是需要利用get的方法,传递给目标tracker网址一些必须的参数,网址接收了这些参数以后会返回数据。
这里有一篇博客详细介绍了这两个地址构造
https://blog.csdn.net/wenxinfly/article/details/1504785
重复的我也没啥好讲了。我就补充一下这篇博客没讲清楚的。
我们可以知道访问http开头的地址的请求构造类似
GET /announce?peer_id=aaaaaaaaaaaaaaaaaaaa&info_hash=
aaaaaaaaaaaaaaaaaaaa&port=6881&left=0&downloaded=100&uploaded=0&compact=1

这里有三点要提醒
1)请求为get请求
2)peer_id是自己随机设定的,只要有20个字节即可
3)这个info_hash,实际上应该是真正的磁力链特征码再经过urlencode得到的。
我们网络上拷贝黏贴下来的磁力链特征码一般是这样的 052ef38011e34ef27e58391da13a327eb88323a3
而这个并不是磁力链特征码的真正样式。只是为了直观显示经过处理后的字符串(因为实际的特征码显示出来会是一串乱码,将上面的字符串,两个字符并成一个就是实际的磁力链了。如,假设我们拷贝的磁力链为”012e“(上面那个太长了,选一个短点的分析,这串编码的二进制流为00000000 00000001 00000010 00001110.那么实际的磁力链二进制编码为00000001 00101110。实际上就是压缩了一下。

更深一步理解为什么要”压缩“一下就要理解以下两点。
1.计算机屏幕上显示的数据和实际数据是不完全等价的。
因为计算机中所有的数据都是二进制流形式,但是我们人却难以理解二进制流的文件。所以就有了编码,将二进制流转化为人能读取的字符流。但是这有一个问题,那就是,实际上二进制01所能表示的”字“数目要多于字符的数目。所以不管哪种编码,那必然会出现有些二进制流乱码,甚至无法编码的问题。所以显示和实际是不完全等价的。
2.加密算法一般都是对于二进制操作。
一般加密算法都是对于01二进制流进行加密的,输入的是01二进制流,输出的也是01二进制流。如上面提到的,二进制流和字符流是不完全等价的。那么就必然有许多字节无法编码成字符。所以加密算法得到的密文一般都是乱码。

磁力链特征码是用sha1加密的->它是一串二进制流->它不能完全编码成任何一种编码(会有乱码)->为了直观显示->将其一个字节拆成两个(这样必然有对应的编码显示)直观显示。

所以对于http开头的tracker请求,我们需要对参数info_hash特殊处理,将其二进制压缩,再编码(这个编码如果不同的话,最后经过urlencode编码得到的数据会不同,我利用utf-8编码是可以实现访问的)得到真正的磁力链字符串,再urlencode。
在php中只要$s= pack(“H*”,info_hash);再$y = urlencode($s);
而java中没有对应的函数,只能自己写了。。。代码放最后。

2.对于udp开头的地址,bt协议对其的介绍在这

http://www.bittorrent.org/beps/bep_0015.html
我一开始以为是udp地址(想起来也是有点蠢。。。

实际地址是udp://后面那部分,例如地址”udp://open.demonii.com:1337“,实际地址为open.demonii.com,端口为1337.
udp开头的地址请求比较麻烦。有一些情况我还不是特别理解,先写下来吧。

首先,这个请求是建立在udp协议之上的,需要用到udp编程
其次数据交互要如下几步走
1.建立连接

我们先要向tracker发送数据包connection_input,包中包括如下几个部分connection_input,action(0,transcation_id(自己定,随机)。connection_id初始值(即建立连接时的值)为0x41727101980(由于数据包是二进制传输的,所以所有的数据都要转为二进制,这个16进制需要转为2进制)。

2.确认建立

得到返回数据包,判断包的字节数是否为16字节,检查连接状态action是否为0,检查transcation_id是否和你设置的一致,保存返回包中的connection_id。

3.发起请求
这次请求数据包比较长,大概100个字节左右,包括connection_id(我们确认建立连接时保存的,action_id(1,表示start),transacation_id(自己定,随机),peer_id(随机),ip(0表示你希望tracker使用udp上的地址),key(随机,自定义)…

4.接收用户下载信息
和2差不多,检查action==1,检查transcation_id.返回数据包中会包含当前正在下载的用户ip以及port。这样就获得了下载ip。

贴上http访问解析后的结果

udp通讯代码
https://github.com/yyyhah/BtDownload/blob/master/Connection/UDPTrackerTransfor.java
http通讯代码
https://github.com/yyyhah/BtDownload/blob/master/Connection/HTTPTrackerTransfor.java
调用演示代码
进行udp开头的地址通讯

 

进行http开头的地址通讯

 

java中16进制字符串转2进制流的函数(我写完这段代码,编译器就报优化bug了,不知道是不是在这段的出错了,如果你也遇到这个问题,百度一下就好了


 

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


举报收藏 0评论 0
0相关评论
相关最新动态
推荐最新动态
点击排行
{
网站首页  |  关于我们  |  联系方式  |  使用协议  |  隐私政策  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号