BitTorrent 伙伴(Peer)协议详解

概述

本文将介绍 伙伴(Peer)协议的握手和通信流程。

伙伴(Peer)协议是一个运行在 TCP 或者 μTP 协议之上的应用层协议,被用于两个 BitTorrent 客户端之间的通信,如上传和下载。使用本协议通信时所有的字符串均使用 UTF-8 编码。

协议可以分为握手流程和通信流程。

握手流程

伙伴(Peer)协议由握手消息和无尽的数据流组成,也就是说协议没有规定断开连接前应该做什么,通信双方随时可以断开连接。

Peer A                                                         Peer B

Handshake
+ String "19:BitTorrAnt protocol"
+ Eight resvered bytes
+ 20 byte bencoded info_hash     
+ 20 byte peer id                  ---------------------->
                                                               Handshake
                                                               + String "19:BitTorrAnt protocol"
                                                               + Eight resvered bytes
                                                               + Same 20 byte bencoded info_hash
                                                               + 20 byte peer id  

                                   <----------------------


Application Data                   <--------------------->     Application Data

握手流程比较简单,A 首先依次发送下列信息。

  1. 字符串 19:BitTorrent protocol
  2. 八个保留的字节,目前的实现中全部为零。
  3. 一个使用 B 编码进行编码的 SHA-1 摘要,此摘要由 .torrent 文件中部分信息计算得出,在不考虑哈希碰撞的情况下每个摘要对应唯一份资源,也就是我们想要下载的资源。
  4. 客户端启动时随机生成的 ID。

B 收到握手消息后应当依次发送下列信息。

  1. 字符串 19:BitTorrent protocol
  2. 八个保留的字节,目前的实现中全部为零。
  3. 一个使用 B 编码进行编码的 SHA-1 摘要,要求于收到的摘要一致。
  4. 客户端启动时随机生成的 ID。

最后双方验证下列信息。

  1. 发送的 SHA-1 摘要和接收到的 SHA-1 摘要是否相同。
  2. 对方的 ID 是否是自己所期望的。客户端一般都通过其它手段(如 Tracker 协议)提前获知了拥有某资源的 Peer ID 列表,如果对方的 ID 不在这份列表内则连接会被关闭。

如果上面两个条件同时满足则握手成功,反之则关闭连接。

通信流程

握手完成后,接下来发送的任何数据都要遵循一个固定的格式,即”长度+具体数据“,也就是发送的数据中,开头是整个信息的字节大小,紧跟在后面的是”具体数据:,整个信息的字节大小不仅包含“具体数据”的大小,还包含开头的“长度”所占用的空间。

通信流程中双方需要保持连接,因此一方可以发送一个长度为 0 的保活(keepalives)消息来确认连接的有效性,并且此消息应该被忽略。一般来说保活消息每两分钟发一次,如果对方有自己需要的数据,则周期可以更短。

任何一个非保活消息都以一个单字节开始,不同的值对应着不同类型的消息,这个单字节被称为消息 ID。通信双方通过这些不同类型的消息来完成资源共享。

消息 ID 有下列取值。

  • 0 – choke
  • 1 – unchoke
  • 2 – interested
  • 3 – not interested
  • 4 – have
  • 5 – bitfield
  • 6 – request
  • 7 – piece
  • 8 – cancel

Choke 消息

此消息不承载任何数据,也就是说发送方只需要发送一个消息 ID 即可。

此消息表示在收到 “Unchoke 消息”之前,对方不会发送任何数据。

Unchokie 消息

此消息不承载任何数据,也就是说发送方只需要发送一个消息 ID 即可。

如果收到了此消息,并且收到了“interested 消息”,则双方会开始数据传输。

Interested 消息

此消息不承载任何数据,也就是说发送方只需要发送一个消息 ID 即可。

此消息表示对方有兴趣进行数据传输。

Not interested 消息

此消息不承载任何数据,也就是说发送方只需要发送一个消息 ID 即可。

此消息表示对方没有兴趣进行数据传输。

Bitfield 消息

此消息承载了一个位图,表示消息的发送方已经下载了哪些数据块,因为数据是被分割为一个个的数据块的,所以可以根据位图的索引确定对方持有哪些数据块。

此消息只能在握手完成后作为首个消息发送,如果没有持有任何数据块则可以不发送此消息。

Have 消息

此消息承载一个数字,这个数字是某个数据块的索引,并且这个数据块是对方刚刚下载完毕并通过校验的数据块。

Request 消息

此消息承载了数据块的索引,数据块内部的起始偏移(字节),和长度。这个长度通常是 2 的幂,除非它被文件末尾所截断。

Cancel 消息

此消息承载了和”request 消息“相同的数据,用于取消之前请求的数据块。通常会在某个数据块即将或已经下载完成时发送,避免对方发送已经下载好的数据。

Piece 消息

此消息承载了数据块索引,数据块内部偏移和具体的数据。


一般来说,客户端应该按照随机的顺序下载每个数据块,随机的顺序有利于让每个客户端持有不同的数据块,这就便于互相交换数据块,加速下载。

当且仅当一方收到了”unchoke 消息“,另一方收到了”interested 消息“时,双方才会启动数据传输。

参考资料

The BitTorrent Protocol Specification

本文作者:ADD-SP
本文链接https://www.addesp.com/archives/5271
版权声明:本博客所有文章除特别声明外,均默认采用 CC-BY-NC-SA 4.0 许可协议。
暂无评论

发送评论 编辑评论


上一篇
下一篇