Torrent
历史
该技术由美国的程序员布莱姆·科亨于2001年4月时发布,并于2001年7月2日时首次正式应用。
原理
普通的HTTP/FTP下载使用TCP/IP协议,BitTorrent协议是架构于TCP/IP协议之上的一个P2P文件传输通信协议,处于TCP/IP结构的应用层。
根据BitTorrent协议,文件发布者会根据要发布的文件生成提供一个.torrent文件,即种子文件,也简称为“种子”。
组成
种子文件本质是文本文件,包括Tracker和文件信息两个部分:
Tracker服务器保存所有正在下载文件的客户端的地址,有人新建连接时,会将地址反馈给新的连接。
文件信息是用Bencode进行编码,是要下载的文件的索引。
Tracker信息
- Tracker服务器地址
- Tracker服务器设置
文件信息
- announce - tracker的URL
- info - 该条映射到一个字典,该字典的键将取决于共享的一个或多个文件
- name - 建议保存到的文件和目录名称
- piece length - 每个文件块的字节数。通常为256KB = 262144B
- pieces - 每个文件块的SHA-1的集成Hash。因为SHA-1会返回160-bit的Hash,所以pieces将会得到1个160-bit的整数倍的字符串。和一个length(相当于只有一个文件正在共享)或files(相当于当多个文件被共享):
- length - 文件的大小(以字节为单位)
- files - 一个字典的列表(每个字典对应一个文件)与以下的键
- path - 一个对应子目录名的字符串列表,最后一项是实际的文件名称
- length - 文件的大小(以字节为单位)
info-hash:每一个种子唯一的编码,由info字段的数据计算而成。
DHT网络
DHT全称为分布式哈希表(Distributed Hash Table),是一种分布式存储方法。在不需要服务器的情况下,每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整个DHT网络的寻址和存储。
磁链
历史
这个标准的草稿出现于2002年,是为了对eDonkey2000的“ed2k:”和Freenet的“freenet:”两个URI格式进行“厂商与项目中立化”(vendor- and project-neutral generalization)而制定的。同时这个标准也尝试紧密地跟进IETF官方的URI标准。
原理
特点:
- 分布式。
- 不依赖于ip地址
- 没有中心服务器
- 开源
组成
磁力链接由一组参数组成,参数间的顺序没有讲究,其格式与在HTTP链接末尾的查询字符串相同。最常见的参数是"xt",是"exact topic"的缩写,通常是一个特定文件的内容散列函数值形成的URN。
magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C
其值是Base32编码的文件的SHA-1散列。
基本描述
magnet:? xl = [字节大小]& dn = [文件名(已编码URL)]& xt = urn: tree: tiger: [ TTH hash(Base32)]
由参数来指定相关的内容:
- dn(显示名称)- 文件名
- xl(绝对长度)- 文件字节数
- xt(eXact Topic)- 包含文件散列函数值的URN。磁力链接的这部分最重要。用于寻找和验证包含着磁力链接中的文件。
- as(可接受来源) - 在线文件的网络链接
- xs(绝对资源)- P2P链接
- kt(关键字)- 用于搜索的关键字
- mt(文件列表)- 链接到一个包含磁力链接的元文件 (MAGMA - MAGnet MAnifest)
- tr(Tracker地址)- BT下载的Tracker URL
- btih(BitTorrent Info Hash):种子的info_hash,转换磁链时就是计算它
开发工具和平台
计算提取info_hash
关键:info字段的值,必须先解码,再对info字段的值编码,然后才计算hash。直接从文件中删除其他部分行不通。
js
bencode库
npm install bencode
如果装了nvm,则-g全局安装会装在.nvm文件夹下。否则,就装在用户目录的node_module下。
sha-1库
npm install js-sha1
实现代码
输出
提取的磁力链接存放在种子目录下名为magnets.txt的文件中
使用
node t2m.js <种子文件夹路径>
js代码
var fs = require("fs");
var bencode = require('bencode');
var sha1 = require('js-sha1');
var arguments = process.argv.splice(2); //获取命令行参数,第三个元素是带的参数
outMagnets(getMagnets(arguments), arguments);
// 获取磁链链接,arguments为文件夹路径
function getMagnets(arguments) {
var fileslist = fs.readdirSync(arguments.toString());
var magnetlist = new Array();
for (var f in fileslist) {
var torrentfile = null;
var filename = fileslist[f].toString();
if (filename.includes(".torrent")) {
var filepath = arguments.toString() + '/' + filename;
var magnet = getInfoHash(filepath);
if (magnet) {
magnetlist.push(magnet);
}
//console.log(magnet);
}
}
return magnetlist;
}
// 将结果输出为txt
function outMagnets(magnets, path) {
if (magnets.length > 0) {
var writebuffer = Buffer.from(arrayToString(magnets, '\n'));
var savepath = path.toString() + '/' + "magnets.txt";
var writesteam = fs.createWriteStream(savepath);
writesteam.write(writebuffer, 'utf-8');
writesteam.end();
writesteam.on('finish', function () {
console.log("写入完成");
});
writesteam.on('error', function (err) {
console.log(err);
});
}
}
// buffer只能输出字符,所以必须将字符数组转换为字符形式,seq为分隔符
function arrayToString(arr, seq) {
var str_value = null;
for (a of arr) {
var astr = a.toString();
if (str_value) {
str_value = str_value + seq + astr;
} else {
str_value = astr;
}
}
return str_value;
}
// 获取种子文件的info_hash值,有一个解密,再加密的过程
function getInfoHash(torrentfile) {
var result = bencode.decode(fs.readFileSync(torrentfile));
if (result) {
var info = result['info']; //info 字典
var info_hash = sha1(bencode.encode(info));
var magnet = "magnet:?xt=urn:btih:" + info_hash.toString();
return magnet;
} else {
return null;
}
}
python
bencode库
gittub
安装:
pip3 install py3-bencode
实现代码
from bencode import bencode, bdecode
from io import BytesIO
import hashlib
objTorrentFile = open("test.torrent", "rb")
decodedDict = bdecode(objTorrentFile.read())
info_hash = hashlib.sha1(bencode(decodedDict["info"])).hexdigest()
print(info_hash)
在解码提取出info后,似乎还需要编码后,再求hash值
参考网址
磁力链接wiki
磁力链接转换为种子文件
官方种子格式说明
种子格式详解
bencode详解
python bencode可用
bencode-gitthub
bencode源码
js-bencode 实现
wiki-bencode
网友评论