bep003-Torrent文件解析.md

目录

  • 前言
    • Bencode 编码
    • metainfo files 文件结构
      • 多文件Torrent的结构
      • 单文件Torrent的结构
    • Tracker 下载客户端上报
    • 后端接收Announce上报接口
      • InfoHashParam注解
  • 总结

前言

我对BT相关协议很感兴趣, 萌生了自己实现一个PT Tracker服务端的想法。 顺便学习下Koitln语言, 于是有了 https://github.com/blanexie/vxph 这个项目, 本项目使用的是 JVM17+Kotlin + Gradle + SpringBoot + Sqlite的框架组合方式。

Bep003 协议是BT协议族的最基础协议。 本篇先讲述下这个协议的内容, 在描述下本项目是怎么实现这个协议的。

  • 协议地址: https://www.bittorrent.org/beps/bep_0003.html
  • 文章中相关代码的开源地址: https://github.com/blanexie/vxph

Bencode 编码

Torrent文件和所有的BT协议中的内容都是使用这个编码的。 具体详细可以百度了解下

协议中的简单描述:

  • 字符串是以长度为前缀的十进制,后跟冒号和字符串。例如,4:spam 对应于“spam”。
  • 整数由“i”表示,后跟以 10 为基数的数字 后跟“e”。例如,i3e 对应于 3,i-3e 对应于 -3。整数没有大小 限度。i-0e 无效。所有带有前导的编码 零,比如 i03e,是无效的,除了 i0e,当然对应于 0。
  • 列表被编码为“l”,后跟其元素(也 bencoded),后跟“e”。例如,l4:spam4:eggse 对应于 [‘spam’, ‘eggs’]。
  • 字典编码为“d”,后跟交替列表 键及其相应的值,后跟“e”。例如,d3:cow3:moo4:spam4:eggse 对应于 {‘cow’: ‘moo’, ‘spam’: ‘eggs’} 和 d4:spaml1:a1:bee 对应于 {‘spam’: [‘a’, ‘b’]}。键必须是字符串,并按排序顺序显示 (按原始字符串排序,而不是字母数字)。
  • 关于字符串的字符集, 十分混乱。 建议还是使用ISO_8859_1进行编码, 中文也是先转成字节数组,在使用这个字符集编码
  • 字节数组的编码,协议中也没有说明, 不过通用的还是先用ISO_8859_1编码成字符串,在使用bencode编码

metainfo files 文件结构

文件结构分两种, 单文件结构和多文件结构

bep003中定义的内容比较少,但是下面的树形结构中内容很多, 多余的内容不用管,都是后面补充协议加上去的

多文件Torrent的结构

├─announce:Tracker的主服务器
├─announce-list:Tracker服务器列表
├─comment:种子文件的注释
├─comment.utf-8:种子文件注释的utf-8编码
├─creation date:种子文件建立的时间,是从1970年1月1日00:00:00到现在的秒数。
├─encoding:种子文件的默认编码,比如GB2312,Big5,utf-8等
├─info:所有关于下载的文件的信息
│ ├─files:表示文件的名字
│ │ ├─length:文件的大小(Byte)
│ │ ├─path:文件的名字,在下载时不可更改
│ │ └─path.utf-8:文件名的UTF-8编码,同上
│ ├─name:推荐的文件夹名,此项可于下载时更改
│ ├─name.utf-8:推荐的文件夹名的utf-8编码,同上
│ ├─piece length:每个文件块的大小(Byte)
│ ├─pieces:文件的特征信息(将所有文件按照piece length的字节大小分成块,每块计算一个SHA1值,然后将这些值连接起来所组成)
│ ├─publisher:文件发布者的名字
│ ├─publisher-url:文件发布者的网址
│ ├─publisher-url.utf-8:文件发布者网址的utf-8编码
│ └─publisher.utf-8:文件发布者的名字的utf-8编码
└─nodes:这个字段包含一系列ip和相应端口的列表,是用于连接DHT初始node

单文件Torrent的结构

├─announce:Tracker的主服务器
├─announce-list:Tracker服务器列表
├─comment:种子文件的注释
├─comment.utf-8:种子文件注释的utf-8编码
├─creation date:种子文件建立的时间,是从1970年1月1日00:00:00到现在的秒数。
├─encoding:种子文件的默认编码,比如GB2312,Big5,utf-8等
├─info:所有关于下载的文件的信息
│ ├─length:文件的大小(Byte)
│ ├─name:推荐的文件夹名,此项可于下载时更改
│ ├─name.utf-8:推荐的文件夹名的utf-8编码,同上
│ ├─piece length:每个文件块的大小(Byte)
│ ├─pieces:文件的特征信息(将所有文件按照piece length的字节大小分成块,每块计算一个SHA1值,然后将这些值连接起来所组成)
│ ├─publisher:文件发布者的名字
│ ├─publisher-url:文件发布者的网址
│ ├─publisher-url.utf-8:文件发布者网址的utf-8编码
│ └─publisher.utf-8:文件发布者的名字的utf-8编码
└─nodes:这个字段包含一系列ip和相应端口的列表,是用于连接DHT初始node

Tracker 下载客户端上报

Tracker可以理解成BT的注册中心, 它记录各个下载客户端信息的服务,
各个客户端也可以从tracker中获取其他下载或者做种的用户。

客户端一般都是使用HTTP GET 请求来上报给tracker信息。 上报的参数如下:

  • info_hash – 这是 .torrent 文件的 info 段的 SHA-1 哈希值,它是个经过 URL 编码的二进制字符串
  • peer_id – 由客户端自行生成的唯一随机 ID,由于在 BT 网络中区分不同的客户端,部分客户端的 peer_id 可能包含不可读字符
  • uploaded – 代表本次会话期间,客户端一共上传了多少字节
  • downloaded – 代表本次会话期间,客户端一共下载了多少字节
  • left – 代表客户端还剩余多少字节等待下载(注意:由于存在校验环节,left 字段仅供参考)
  • event – 代表该 torrent 的事件, 可选字段。 事件列表 :
    • started 种子开始下载
    • completed 种子下载完成,开始做种
    • stopped 种子停止下载 / 做种,不再活动
    • empty 和没有此字段的情况完全相同

约定俗成的请求路径为 /announce , 下面是一个真实请求示例: 示例中包含有很多其他的字段,不用管都是BT其他协议引入的
GET /announce?info_hash=j%25%7c%fe%12%0e%c0%9d%ee6%d5%df%03%bb%fda%cd%7b%97%b5&peer_id=-qB4510-1MTFo0SteXN2&port=22387&uploaded=0&downloaded=0&left=0&corrupt=0&key=332CA113&event=started&numwant=200&compact=1&no_peer_id=1&supportcrypto=1&redundant=0&ipv4=198.18.0.1&ipv6=2408%3a8214%3a2e11%3a8cb1%3a%3a9b8&ipv6=2408%3a8214%3a2e11%3a8cb1%3a7c27%3acac2%3a3b51%3a42fb&ipv6=2408%3a8214%3a2e11%3a8cb1%3ae0e7%3a8eb%3a4677%3a21f0

后端接收Announce上报接口

bep003-Torrent文件解析.md_第1张图片

InfoHashParam注解

由于infoHash是一个20长度的字节数组, Qbitorrent客户端上报的infoHash字段中,SpringBoot的默认参数解析无法正确接码,于是我自定义了接口参数注解和解析方式。

也许有更好的解决方案,但是我不清楚。 希望知道的人指点。

  • InfoHashParam 注解定义bep003-Torrent文件解析.md_第2张图片

  • InfoHashRequestParamResolver 参数解析类
    在这个类中会识别判断@InfoHashParam 并从URL中截取出来参数解析
    bep003-Torrent文件解析.md_第3张图片

  • 装配到Spring框架中

bep003-Torrent文件解析.md_第4张图片

  • infoHash解码方法。 从网络上抄来的方法。
    bep003-Torrent文件解析.md_第5张图片

总结

Bep003协议还包含其它内容, 比如Peer相关的内容, 但是由于我想做的只是Tracker服务,所以文章中没有描述。

项目中使用到了SaToken作为鉴权方式, 但是由于SaToken还不支持Java17版本,于是我修改了SaToken的相关类使得兼容17。 具体内容会在下篇文章中详述。

你可能感兴趣的:(BT,spring,boot,kotlin,sqlite)