我希望构建一个简单的最小bittorrent客户端。 我现在阅读协议规范2-3天了。
这是我迄今为止对它的理解。假设torrent的片段长度为26000 bytes
,并且根据非官方规范块大小为16384
。这样的事情。
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部分的一部分)再次重新传输。
现在突然间,块和块分布变得有点复杂,然后我认为它是。我希望有一个更简单的解决方案。
任何想法
答案 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[]):()
然后,您将能够读取/写入任意数据子范围。