想做个磁力链搜索引擎 2

news/2024/10/31 9:29:33/

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

上一篇中我们解析种子发现有两个键比较特殊,分别时announce以及announce-list
在这里插入图片描述
这两个属性的值便是是tracker服务器的地址。(据我观察,announce里面的地址比announce-list里面的地址访问速度快一点,announce-list里的地址无法访问的概率大一点)

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访问解析后的结果
在这里插入图片描述
我这里是设置了,一次获取10个ip,如果没设置numWant参数,一次默认最多50个

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

	UDPTrackerTransfor udpTf = new UDPTrackerTransfor(10000,"bf917a3e5bc740c316f8bb16129da394cc732bdb");byte[] bytes = udpTf.setUpLink("udp://tracker.openbittorrent.com:80");System.out.println(bytes.length);for(byte b:bytes) {System.out.print(b);System.out.print(" ");}byte[] bytes2 = udpTf.startAnnounceRequest();for(byte b:bytes2) {System.out.print(b);System.out.print(" ");}

进行http开头的地址通讯

	HTTPTrackerTransfor httpTf = new HTTPTrackerTransfor();try {String data = httpTf.setUpLink("http://tracker.supertracker.net:1337/announce", hash, port);System.out.println(data);}catch(Exception e) {System.out.println("该链接无法访问!!!");}

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

public static byte[] HexToByte20(String inHex) {byte[] hexBytes=new byte[20];int index = 0;while(inHex.length()<40) {inHex = "0"+inHex;}for(int i=0;i<inHex.length();i=i+2) {int n = Integer.parseInt(inHex.substring(i,i+2), 16);hexBytes[index] = (byte)(n&0xff);index++;}return hexBytes;}

ps:最后再提几点需要注意的地方
1.有些人(比如我)一开始向udp的tracker发出请求只能获得一个(就是自己本地ip)。如果你也遇见这个问题,检查一下hashInfo转化有没有出错。刚开始我就是出错了。我上面那段代码经过抓包检验,应该时没问题了。
2.虽然上面udp tracker给了这么多个ip地址,实际上经过检验,能ping通的没几个,我就因为tcp连接一致连不通,一直以为我弄错了。。。。这里对要进行下一步peer之间的通讯实验的人做个提醒。


http://www.ppmy.cn/news/434286.html

相关文章

win7台式计算机型号怎么查,win7系统电脑查看主板型号的四种方法

刚刚购买新的电脑安装win7旗舰版系统&#xff0c;新手对电脑信息肯定不太了解&#xff0c;如果知道主板型号就知道电脑的全部信息了&#xff0c;也有助于我们了解电脑的配置&#xff0c;方便以后使用。那么win7系统电脑如何查看主板型号&#xff0c;相信很多小伙伴都不知道如何…

cmd命令查询电脑序列号_如何查看台式电脑序列号

展开全部 方法一&#xff1a; (1)如果是win10系统&#xff0c;可以在键盘上同时按下winr键&#xff0c;打开命令提示符&#xff0c;并32313133353236313431303231363533e59b9ee7ad9431333431333935输入cmd&#xff0c;点击确定或回车 (2)在弹出的页面中输入“systeminfo”并按下…

win7台式计算机型号怎么查,win7怎么看电脑型号 win7电脑型号怎么查

有许多新用户不知道如何查看电脑型号&#xff0c;我们以目前最常用的系统win7为例给大家介绍一下&#xff0c;如何查询电脑型号&#xff01; 小提示&#xff1a; 1、一般组装电脑没有电脑型号&#xff0c;您只能查到组装电脑的各配件的型号&#xff0c;比如&#xff1a;CPU、显…

论文浅尝 | 用于推荐的知识自适应对比学习

笔记整理&#xff1a;俞洪涛&#xff0c;浙江大学硕士&#xff0c;研究方向为知识图谱表示学习 链接&#xff1a;https://dl.acm.org/doi/10.1145/3539597.3570483 动机 在基于知识图谱的推荐系统中&#xff0c;用户和项目的交互信息通常会在模型中占主导地位&#xff0c;而KG中…

台式台式计算机型号怎么看,怎么查看电脑的型号和配置,台式电脑设备型号在哪里看...

台式电脑怎么看型号? 台式机有型号(如联想台式机),而台式机装配工一般没有型号(如购买显卡、内存、CPU、硬盘、主板组装的台式机)。有两种方法可以查看桌面模型。方法一:直接检查:检查电脑主机或包装盒的标签,如果是品牌桌面,则在标签上标注;方法二:下载软件:1。下载鲁…

2024考研计算机408数据结构+操作系统+计算机组成原理+计算机网络

2024考研计算机408数据结构操作系统计算机组成原理计算机网络 链–接&#xff1a;https://pan.baidu.com/s/1CjUlIDctKVqnY9VIeHU9dA?pwdw13l 提–取–码&#xff1a;w13l 这是我给大家整理的四零八中&#xff0c;并查集可能考察的地方。并查集作为二二考研中新增加的考点。…

Java并发编程之显式锁机制

一、接口Lock的基本组成成员 Lock 位于java.util.concurrent.locks包下&#xff0c;源码如下&#xff1a; public interface Lock {void lock();void lockInterruptibly()boolean tryLock();boolean tryLock(long time, TimeUnit unit)void unlock();Condition newCondit…