如何在重叠时分块

时间:2017-06-02 08:48:02

标签: bittorrent

我希望构建一个简单的最小bittorrent客户端。 我现在阅读协议规范2-3天了。

这是我迄今为止对它的理解。假设torrent的片段长度26000 bytes,并且根据非官方规范块大小16384。这样的事情。

enter image description here 现在根据块块消息的请求看起来像这样

piece 0 
block offset 0
block length 16484

到目前为止一切顺利。

现在,对于在0和1中重叠的下一个块,请求应该是什么样的

piece 0  ## since the start of byte is in piece 0 use piece 0 instead of piece 1
block offset 16384
block length 16384

现在在接收端,我需要重新创建26000字节的片段,以便我可以将它与片段(散列)进行比较,以匹配片段的正确性。

我的理解是否正确?

此外,我想假设片断验证失败,可能是因为第一个块,即块0(有故障或损坏) 然后我应该重新排队Block 0和Block 1(这是有效的btw,也是第1部分的一部分)再次重新传输。

现在突然间,块和块分布变得有点复杂,然后我认为它是。我希望有一个更简单的解决方案。

任何想法

3 个答案:

答案 0 :(得分:1)

  

将使用更明确的术语' chunk '而不是模糊的' '。

  • 洪流分为几部分。

  • 一件被分成几块。

  • 从一块上切下一块。

创建时,torrent会被分成几部分。通过请求消息,通过下载BitTorrent客户端,一块又被分成块。
只要没有单个块大于16 KB(16384字节),客户端如何从块中切出块并不重要。
分割片段的最简单和最合理的方法是,在尽可能少的块中进行分割,将其分成16 KB块,并在必要时让片段的最后一块更小。

  

请求邮件格式:<len=0013><id=6><Piece_index><Chunk_offset><Chunk_length>

     
      
  • <Piece_index >整数,指定从零开始的片段索引
  •   
  • <Chunk_offset>整数,用于指定
  • 中基于零的字节偏移量   
  • <Chunk_length>整数,指定所请求的字节数
  •   



请求块时:

  • 整个块必须位于Piece_index 指定的部分内,
    Chunk_offset + Chunk_length必须小于或等于特定作品的大小*。
  • Chunk_length不能大于16 KB(16384字节)且必须至少为1个字节
  • 获取请求的对等方必须具有Piece_index
  • 指定的作品

如果未满足任何条件,则接收请求的对等方将关闭连接。

*除了最后一个 info -dictionary中定义的'piece length'之外的所有作品。
最后一块的大小可以计算如下:
size_last_piece = size_of_torrent - (number_of_pieces - 1) * 'piece length'

答案 1 :(得分:0)

客户端通常接受的最大块大小为16KiB。客户可以自由提出较小的请求。

碎片通常是16KiB的倍数,但是当前的规格不需要它(这会随着BEP52而变化)并且有些人使用素数或类似的东西来获得乐趣,所以它们确实存在于野外。 / p>

块仅存在于您需要多个请求以获得大于16KiB的完整块的意义上。换句话说,块与您决定请求的内容相同。你可以请求500个字节,然后是1017个字节,然后是13016个字节,......直到你得到一个完整的部分。它们是中的任意细分 - 没有重叠 - 您需要在下载作品的开始和完成作品之间进行跟踪。

他们不参与散列,他们不会考虑HAVE或BITFIELD消息。只有REQUEST,PIECE,CANCEL和REJECT消息与块有关。而不是块,你也可以称它们为子片段偏移长度元组或类似的东西。

答案 2 :(得分:-1)

一块中的最后一块可能小于传输块大小。即应在第二个PIECE消息中请求26000 - 16384 = 9616个字节。一旦收到所有26000个字节,就应计算SHA-1哈希,并与metainfo字典的pieces部分的相应校验和进行比较。如果校验和不匹配,则无法知道哪个块包含无效数据,并且应该从该块中重新下载所有块。

我的建议是不要依赖于某件作品的特定分区,因为: 1)对等体在请求数据时可以使用不同的传输块大小 2)SHA-1算法是基于块的,并且消化器更好地使用更大的块大小(否则计算将花费更多时间)

对于一个片段的正确抽象将是通用data range,具有以下方法:

  • read(from:int, length:int):byte[]
  • write(offset:int, block:byte[]):()

然后,您将能够读取/写入任意数据子范围。