在上一节中我们讲到了 GetBlocks 接口, 在收到 Keys 请求之后, 会通知各个模块缓存关于 KEYS 的请求, 并且开始通过路由层来寻找对应的数据. 在将 KEYS 存入 WantManager 的同时, WantManager 会把已经建立链接的节点信息存储在一个 Map 中, 当收到 GetBlocks 请求之后, Want Manager 会马上将这些请求发送给这些节点, 下图是节点信息的 Map 数据结构.
可以看到每一个节点的 PeerID 对应一个 Message Queue,Message Queue 由 2 个部分组成, 一个是 Want List 一个是 Out Queue.Out Queue 里面又有一个 Want List 和一个 Block List,Want List 存储的是 key 对应的请求, Block List 存储的是 Key 对应的数据.
每一个消息队列都有自己的 run loop, 当有新的查找指令到来时, run loop 负责将查找指令通过 msgSender 对象发出, 因为我们使用的是 Peers 这个 Map, 因此我们知道命令接收者的 peer id, 将该 id 传给 Message sender 对象之后, 它就可以通过网络层建立链接并将查找指令传递给消息接受者.
以上是对已经与本节点建立链接的节点, 接收本节点的查找命令的逻辑, 我们在前一节重点讲解了接收到查询命令之后, 各个缓存存储查找指令的方式, 以及各个缓存自己的 run loop 是如何逐步的执行数据查询命令的. 接下来我们讲解作为被查询节点, 当接收到这些查询命令之后是如何响应的.
首先我们假设其实状态下, Want Manager 并不管理任何其它节点信息, 我们在前面的章节中说过, GetBlocks 有一个选择是将被查询对象的 KEY 的数组的第一个 KEY 作为对象调用 findkeys(), 上图是前面流程的概要图, 并增加了其它节点收到这个链接请求后的动作, 首先其他节点与本节点建立数据链接, 成功建立链接之后, IPFS 的协议层会将其它节点的信息加入到 Want Manager 的其它节点列表中进行管理. 上图就是每一层协议的关键处理函数.
当获得其他节点信息之后, 我们知道有一个 RUN LOOP 会发起 Send Message 请求, 本节点会将需要查找数据的 KEY 值发送给所有可用的其他节点上, 这些请求被发送的其它节点. 其它节点收到这个数据查询请求之后, 通过网络层接受数据, 并将数据组合为数据交换层能够理解的 BitSwapMessage 数据格式. 然后将数据放到 Engine 这个模块的一个队列中, 这个队列叫做 PeerRequestQueue.
上图就是 PeerRequestEngine 的数据结构, 他保留一个列表, 用来出出具体的数据, 一个 TaskMap 用来管理请求任务, 每一个接受的数据都会被封装成为一个任务. 还有两个 Map 分布用来存储发送请求过来的对端的信息, 一个是正常的 partners 的 Map, 另一个是被冻结的 Partner 的 Map, 在 IPFS 的数据交换协议里面, Engine 会管理本节点与其它节点的数据交换的数量, 以防止恶意攻击, 如果一个节点只获取数据, 并不提供数据, 那么这个节点可能会被其它节点加入到冻结列表中.
这个数据请求队列也有一个 Run Loop, 不停地检查是否有工作, 按照顺序将处在队列头的请求 Pop 出来, 得到一个请求的任务 task, 然后节点通过查找本地的数据存储, 将 task 中存储的数据请求 key 取出, 在寻找 key 对应的具体数据 block, 得到这个数据之后, 调用 WantManager 的 SendBlock 接口, 将数据发送到网络上. 接下来的章节我们将讲解当请求数据的节点接收到其他节点发送来的 key 对应的数据会如何处理.
来源: http://www.jianshu.com/p/2283674d4d14