【bep0005协议】简介

原文

bep_0005.rst_post

简介

该协议主要介绍了路由表的结构和相关操作,torrent文件的一个新的扩展字段nodes,以及基于KRPC协议的四个请求—ping、find_node、get_peers、announce_peer。

前置知识

peer和node

peer是一个监听TCP端口并实现了BitTorrent协议的Client/Server,node是一个监听UDP端口并实现了DHT协议的Client/Server。DHTnodes组成,保存peer的位置信息,用来从其他的peer中下载需要的文件。

node id

每个node都有一个全局唯一的标识id,这个id是sha1算法的结果,也就是160个bit(这个nodeid可以随机生成)。在此基础上,规定如果要计算两个node或一个node和某个文件infohash的距离,只需要对他们进行异或操作就可以了。

路由表

路由表维护了网络中已知的可达的好节点。路由表包含了 0 − 2 160 0-2^{160} 02160范围内的节点id列表,路由表又被分为桶,每个桶可以放 n n n个节点,当前的 n = 8 n=8 n=8,其实本质上就是一棵做了一些变形的二叉树。向路由表中放入节点信息时,有以下几种策略:

  1. 如果对应的桶中都是好节点,新的节点就被简单的丢掉;
  2. 如果桶中有任意的节点损坏,就需要把新的节点替换掉某个旧的节点;
  3. 如果某个桶中在过去15分钟内都没有出现可以节点,则按照更新时间从远到近逐个发起ping请求,知道发现一个坏节点或全部为好节点,将坏节点用新节点替换。另外建议在用新节点替换之前最好再ping一下旧的坏节点;
  4. 路由表中的节点每次发送回复消息时都应该刷新它的更新时间。
  5. 节点首次启动时,应该向已知节点发送find_node消息来初始化路由表。

实际上为了保证节点与网络中其他节点的紧密性,一般不会轻易的删除路由表中的节点。

BitTorrent协议拓展

在BitTorrent协议中引入了对于reserved字段的一个扩展,用来交换两个peer的node之间的UDP端口号。Handshake的reserved字段的最后一位表示是否支持DHT,如果支持则应该发送一个PORT消息,以0x09开始,后面跟着两个byte表示UDP端口。接受方收到端口消息之后应该向这个端口发送一个ping消息,如果收到ping消息的响应,则应该将这个node加入路由表。具体实例参考【bep0003协议】简介peer messages部分。

torrent文件扩展

如果一个torrent文件没有announce字段,那么应该要有一个nodes字段,值是距离生成该torrent文件的peer的路由表中与其距离最近的若干个好节点的compact形式的[ip][port]信息。

KRPC协议

一种简单的RPC机制,有三种类型的消息:查询、响应和错误,对于DHT有四个查询:ping、find_node、get_peers和announce_peer。消息体是一个bencode编码的字典,消息体中会有以下几个公共键:t表示该消息的事务id,一般2个字节就够了;y表示该消息的类型,值可以是q表示查询,r表示回复,e表示错误;v表示客户端的类型,这个键是可选的。

peer的信息是一个6byte的String,前4个byte表示ip地址,紧接着的2个byte表示端口号;node的信息是一个26byte的String,前20个byte表示该node的id,也就是sha1哈希的结果,紧接着的4个byte是ip,最后2个byte是端口。其中前者称为Compact IP-address/port info,后者称为Compact node info

查询query

y的值为q表示消息表示该消息是一个查询,这种类型的消息还会有一个键qa,其中在DHT中q的值可以是ping、find_node、get_peers或announce_peer,针对不同的消息,a的值也不同,后面会介绍到。

回复response

y的值为r表示该消息是一个请求的回复,这种类型的消息会有一个键rr的值是回复的消息的具体数据,在DHT中不同请求的回复消息也是不同的,后面有介绍。

错误error

y的值为e表示错误消息,这种类型的消息会有一个键ee的值是一个List,List中有2个元素,第一个元素为错误代码,第二个元素为错误的描述信息,可能的错误代码如下:

错误代码描述信息
201Generic Error
202Server Error
203Protocol Error, such as a malformed packet, invalid arguments, or bad token
204Method Unknown

比如:
generic error = {“t”:“aa”, “y”:“e”, “e”:[201, “A Generic Error Ocurred”]}
bencoded = d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee

报文

在这里插入图片描述

基于KRPC的DHT

所有的查询都有一个id表示发起请求方的node id,所有的回复也有一个id表示回复方的id

ping

参数

ping消息用来检测一个node是否可用,类似命令行中的ping命令。示例:

ping Query = {"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}}
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re

对于请求消息,t表示消息的事务id,y固定为qq固定为pinga中固定只有一个请求方的id
对于回复消息,t表示消息的事务id,应该与对应的请求消息的事务id相同,y固定为rr中固定只有一个回复方的id

报文

请求

在这里插入图片描述

回复

我使用的客户端不会回复其他客户端发送的ping请求。

find_node

参数

find_node主要用来向某个peer请求其路由表中target节点的信息或与target距离最近的K(默认8)个节点的compact node info信息。示例:

find_node Query = {"t":"aa", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456"}}
bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t2:aa1:y1:qe
Response = {"t":"aa", "y":"r", "r": {"id":"0123456789abcdefghij", "nodes": "def456..."}}
bencoded = d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t2:aa1:y1:re

对于请求消息,t表示消息的事务id,y固定为qq固定为find_nodea中固定有一个请求方的id和一个目标的target
对于回复消息,t表示消息的事务id,应该与对应的请求消息的事务id相同,y固定为rr中固定有一个回复方的id,以及compact node info形式的目标信息或距离目标最近的K个节点的信息nodes

报文

请求

在这里插入图片描述

回复

我使用的客户端不支持发送和响应find_node请求。

get_peers

get_peers主要用来获取torrent的文件哈希相关联的peer信息,如果查询的节点中有目标peer信息,则在r中以values的形式返回,否则会返回与目标哈希最近的K个节点。示例:

参数

get_peers Query = {"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456"}}
bencoded = d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe
Response with peers = {"t":"aa", "y":"r", "r": {"id":"abcdefghij0123456789", "token":"aoeusnth", "values": ["axje.u", "idhtnm"]}}
bencoded = d1:rd2:id20:abcdefghij01234567895:token8:aoeusnth6:valuesl6:axje.u6:idhtnmee1:t2:aa1:y1:re
Response with closest nodes = {"t":"aa", "y":"r", "r": {"id":"abcdefghij0123456789", "token":"aoeusnth", "nodes": "def456..."}}
bencoded = d1:rd2:id20:abcdefghij01234567895:nodes9:def456...5:token8:aoeusnthe1:t2:aa1:y1:re

对于请求消息,t表示消息的事务id,y固定为qq固定为get_peersa中固定有一个请求方的id和一个目标的info_hash
对于values类型的回复消息,t表示消息的事务id,应该与对应的请求消息的事务id相同,y固定为rr中固定有一个回复方的id,以及一个简单的token,以及List形式的目标信息values
对于nodes类型的回复消息,t表示消息的事务id,应该与对应的请求消息的事务id相同,y固定为rr中固定有一个回复方的id,以及一个简单的token,以及compact node info形式的距离目标最近的K个节点的信息nodes

回复字段a中的tokenannounce_peer消息中会被用到。

报文

请求

在这里插入图片描述

values类型回复

在这里插入图片描述

nodes类型回复

在这里插入图片描述
在这里插入图片描述

announce_peer

参数

announce_peer用来告诉其他peer,当前peer控制的某个节点正在下载某个info_hash对应的文件。参数列表为:

arguments:  {"id" : "<querying nodes id>",
  "implied_port": <0 or 1>,
  "info_hash" : "<20-byte infohash of target torrent>",
  "port" : <port number>,
  "token" : "<opaque token>"}

response: {"id" : "<queried nodes id>"}

其中id为发送方的id,info_hash为该文件的info_hash,port为端口,token就是get_peers中使用的token。接收方接收到该数据之后会检查自己保存的token信息以及与该token对应的ip和端口信息是否相同,如果相同会将这个发送方的ip和port保存到对应的info_hash信息中,表示这个ip和port对应的发送方正在下载info_hash对应的文件。
implied_port为可选项,值为0或1,如果该键被设置为1,表示接收方后面在保存发送方信息的时候,应该忽略掉port字段,而使用发送方发送数据的端口。

回复方回复的消息r中只有一个id

示例:

announce_peers Query = {"t":"aa", "y":"q", "q":"announce_peer", "a": {"id":"abcdefghij0123456789", "implied_port": 1, "info_hash":"mnopqrstuvwxyz123456", "port": 6881, "token": "aoeusnth"}}
bencoded = d1:ad2:id20:abcdefghij012345678912:implied_porti1e9:info_hash20:mnopqrstuvwxyz1234564:porti6881e5:token8:aoeusnthe1:q13:announce_peer1:t2:aa1:y1:qe
Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re

报文

请求

在这里插入图片描述
在这里插入图片描述

回复

在这里插入图片描述


总结

有一些dht爬虫在实现的时候主要会考虑实现该协议,假装自己是一个正常的peer节点,通过不断的向其他节点发送find_node请求,不断在dht网络中“交朋友”,有些节点就会向本节点发送get_peers请求,通过拿到get_peers请求中的info_hash就得到的一个文件信息。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值