【bep0003协议】简介

原文

bep_0003.rst_post

简介

协议详细介绍了torrent文件的内容,如何通过torrent文件从dht网络中获取到对应的文件等内容。

协议介绍

bencode

bencode编码还是比较简单的,只是一些简单的数据处理。bencoding基于4种类型:StringIntegerListDictionaries

String

字符串的编码只是在原来的字符串前面加了一个字符串长度和分隔符 : : :

String编码示例如下:

String
- Hello World
bencode 编码后的 String
- 11:Hello World
11就是字符串的长度

Integer

Integer的编码只是在原来的数字前后分别添加一个字符ie

Integer编码示例如下:

Integer
- 1234
bencode编码后的Integer
- i1234e

List

List的编码只是在原来List的首尾分别添加了一个le

List是元素类型为StringIntegerListDictionaries的数组或链表,示例如下:

List
- ["hello", 1234]
bencode 编码后的 List
- l5:helloi1234ee

Dictionaries

Dictionaries的编码只是在原来List的首尾分别添加了一个de

Dictionaries是一个哈希表,协议中规定了key一定是String,并且哈希表中的key-value对按照key的字符串原来的顺序排序,示例如下:

Dictionaries
- {"b" : 123, "a" : "hello"}
bencode 编码后的 Dictionaries ,这里key的a在前b在后
- d1:a5:hello1:bi123ee

metainfo file

这块就是torrent文件了,torrent文件本质上就是一个Dictionaries,里面主要是对对应文件的描述内容,包括文件名、大小、创建时间以及分片信息等等。

announce字段

value是一个String,表示tracker url。

info字段

keyvalue字段描述
nameUTF-8类型的String建议和当前torrent文件的名字相同
piece lengthInteger,表示每个文件分片的大小该字段应该是2的幂次方,常见的有 2 18 = 256 K 2^{18}=256K 218=256K 2 20 = 1 M 2^{20}=1M 220=1M
piecesString长度为20的倍数,第i个20长度的字符串表示第i的文件片的sha1哈希
lengthInteger,可选和下面的files只能同时出现一个,length出现时表示是个单文件
filesDict,可选和上面的length只能同时出现一个,files出现时表示该torrent中有多个文件

files字段的内容如下

keyvalue字段描述
lengthInteger子文件长度,单位为byte
pathList子文件内容

torrent文件解码示例

其中的List仅展示2个作为参考,另外为了避免溢出,所有数字都解码为Long类型。

多文件torrent

下面是一个多文件torrent。

解密后的某个鱿鱼游戏的torrent文件

单文件torrent

下面是一个单文件torrent

单文件torrent

对比

通过对比,可以发现多文件torrent中会有一个files字段描述每一个文件的信息,单文件torrent中则是一个length字段。

扩展协议

上述为标准torrent文件字段,除了上述字段之外,还有一些扩展协议对torrent文件内容进行了一些扩展,增加了一些比较有用的字段。

announce-list

来自bep_0012.rst_post,该协议在torrent文件中引入了一个announce-list字段。关于该字段的一些规范如下:

  1. 值是一个List,List中的元素也是List,协议中叫做tiertier也是一个List,tier的元素是tracker url;
  2. 出现该字段时,将自动忽略announce字段的URL,而选择使用announce-list字段的URL;
  3. announce-listtier将会被按顺序使用,第一次读取一个tier的时候,将会按照随机的顺序使用tier中的url,如果这个url有响应,会被移动到tier的第一个位置,否则继续使用下一个。
private

来自bep_0027.rst_post。生成torrent文件时,在info字段中添加private=1表示该torrent是一个私有的,针对该类torrent文件,只能向私有tracker发送announce请求,并且只能和私有tracker返回的peer发起连接。对于announce-list字段中的tracker,每次只能使用其中的一个tracker,无论是在tracker之间切换还是建立连接。

httpseeds

来自bep_0017.rst_post

值是一个List,List中包含有若干个URL,客户端可以根据这些URL下载种子数据,如果获取不到的话,客户端会自动忽略这些URL。获取种子数据的URL格式为:

<url>?info_hash=[hash]&piece=[piece]{&ranges=[start]-[end]{,[start]-[end]}…}
比如:
http://www.whatever.com/seed.php?info_hash=%9C%D9i%8A%F5Uu%1A%91%86%AE%06lW%EA%21W%235%E0&piece=3
http://www.whatever.com/seed.php?info_hash=%9C%D9i%8A%F5Uu%1A%91%86%AE%06lW%EA%21W%235%E0&piece=8&ranges=49152-131071,180224-262143

tracker

tracker服务器就是常见的形式[udp|http|tcp]: //url:port/announce。tracker一般指一个http服务器,对外提供下载查询服务,添加了指定字段之后可以像访问一般的http服务器一样去访问tracker服务器。

请求

向tracker服务器发送的一个GET请求主要包括以下字段:

字段描述
info_hash20byte的SHA1算法加密后的字符串
peer_id下载者使用的20byte的描述自身的id
ip可选
port端口
uploaded已上传
downloaded已下载
left剩余的还没有下载的字节数
event可选,值为started、completed或stopped\empty

wireshark抓了个数据包,可以参考下,大致还是能看出来一些字段的
wireshark简单抓包

回复

tracker服务器的回复是一个bencode编码的Dict。

回复信息分为两类,这两类的区分是根据返回的消息中是否含有一个failure reason字段,该字段对应一个友好的String类型的提示来解释为什么请求失败。

另外,有两个字段是必需的,分别是intervalpeers,其中前者对应一个数字,表示在重新请求之间对应的秒数(which maps to the number of seconds the downloader should wait between regular rerequests.);后者对应一个Dict组成的List,每个Dict包含一个String类型的peer id、String类型的ipdns地址以及Integer类型的port,如果一个事件发生或者需要更多的peer信息,下载器可以在非规定时间内重新请求(Note that downloaders may rerequest on nonscheduled times if an event happens or they need more peers.)。

通常情况下tracker服务器会返回一个紧凑形式的peer list,具体来说就是可以通过在向tracker服务器发送GET请求时,添加一个compact字段来进行控制,当compact=0时,tracker服务器返回原始形式的peer list;compact=1时,tracker服务器返回紧凑形式的peer list。但是这个只是建议性的,tracker服务器可能并不会根据你的compact字段来返回对应形式的peer list,但是多数的客户端都是支持的。具体可以参考bep_0023.rst_post

请求中服务器的回复

在这里插入图片描述

peer protocol

该协议基于TCP或uTP/bep_0029.rst_post

这块主要介绍了Handshake数据包,handshake首先是一个数字19,后面跟着一个String,即BitTorrent protocol;紧接着是叫做reserved的8个byte的保留字,有些客户端使用了一些扩展协议会用到这些保留字,一般情况下全设为0;接下来是20个byte的sha1哈希,这个是torrent中文件片的哈希;紧接着是20个byte的peer id。如下:

握手协议

握手协议内容

reserved字段并不全为0,说明该客户端实现了一些扩展协议。

peer messages

下面是Hanshake成功之后,两个peer间通信的消息。消息是长度和消息内容的流,格式为[length][data],其中length长度为4个byte,表示data的长度(单位:byte)。data有两种形式,一种是只有某种标志位,另一种是除了标志位之外还有该标志所需要的参数,针对不同的类型进行相应的处理即可。一个数据包可能包含多个消息,如图:

peer消息
可以看出,该报文带有3个peer消息,并且第三个消息的length字段的16进制表示为00 00 00 03,也就是3,表示后面有3个byte的数据,第一个byte为09,即0000 1001,这种类型应该表示后面会有一个端口,后面2个byte就表示端口了, 1 a e 1 = 1 ∗ 1 6 3 + 10 ∗ 1 6 2 + 14 ∗ 16 + 1 = 4096 + 2560 + 224 + 1 = 6881 1ae1=1*16^3+10*16^2+14*16+1=4096+2560+224+1=6881 1ae1=1163+10162+1416+1=4096+2560+224+1=6881。关于这个port消息可以参考【bep0005协议】简介中的BitTorrent协议扩展部分。
其他同理。

所有的非keepalive消息都以一个byte的数据开始,来表示这个消息的类型,主要包括以下几种类型:

类型描述
0choke没有其他字段
1unchoke没有其他字段
2interested没有其他字段
3not interested没有其他字段
4have表示文件片下载完成;只有一个字段,即刚刚下载完成并检查了hash值之后对应torrent中文件片的索引
5bitfield如果文件设置了分片,作为Handshake后的第一个消息发送,字段本质上是一个位图,以byte为单位,当前客户端已经下载的记为1,没有下载的记为0,按照torrent文件中的文件片索引顺序依次设置,最后一个byte多余的部分填充0;如果文件没有分片,则可以跳过该消息
6request向其他客户端请求文件片;有三个字段,分别是文件片索引(piece index)、文件片开始索引(begin)、从文件片开始索引位置开始要获取的文件长度(length),除了最后部分的内容外,其余部分的length都应该是2的幂次方,目前的实现都是 2 14 2^{14} 214即16KB
7piece是request消息的响应;包含三个字段,分别是分别是文件片索引(piece index)、文件片开始索引(begin)和具体的文件内容(content),其中前两个字段和对应的request消息内容一样,而content则是对应的文件内容
8cancel下载即将结束的时候使用;与request字段相同

choke和unchoke以及interested和not interested是控制双方下载状态的标志位,通过设置不同的标志位可以实现不同的下载状态。

另外关于标志位的更多内容可以参考bep_0004.rst_postReserved Message IDs部分,有介绍其他的一些标志位信息,在bep_0006.rst_post中,有部分扩展的详细解释。

wireshark抓取的报文

bitfield

在这里插入图片描述


bep0003协议大概就是这个样子。

总结

该协议详细介绍了torrent文件的结构以及对应字段的含义,如何与tracker服务器交互来获取当前与对应哈希文件相关联的peer信息,以及如何与这些peer建立连接并获取对应哈希的文件片内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值