eMule(电骡)使用多种方法来确保网络中下载和共享的文件没有错误。当错误发生时,或称作损坏时,eMule拥有的高级功能仅需要重新下载最少量的数据就能修复这种损坏。
文件Hash和ICH - 智能损坏处理
文件Hash,文件段Hash值和Hashset
每一个被共享的文件在网络中都会由MD4数学加密算法计算出一个理论上唯一的特征值。这个数值被称作文件Hash值(也作:哈希),并且被包含在每个标准的eD2k链接中。例如:ed2k://|file|name|12043984|6744FC42EDA527B27F0B2F2538728B3E|/
其中6744FC42EDA527B27F0B2F2538728B3E就是该文件的文件Hash值,也即文件在网络的独一无二的特征值。
文件Hash值通过将文件分割成每个9.28 MB的文件段然后计算得来,每一个文件段都用相同的MD4算法得到一个文件段Hash值。用这些被称作Hashset的文件段Hash值,可以接着计算出最终的文件Hash值。例如,一个600MB的文件将被切分成65块文件段,每一个都有自己的文件段Hash值,然后用它们计算得到最终的文件Hash值。
为了确保eMule始终接收到正确的Hashset,可以创建一个特殊的包含Hashset的链接,例如:
ed2k://|file|name|12043984|6744FC42EDA527B27F0B2F2538728B3E|p=264E6F6B587985D87EB0157A2A7BAF40:17B9A4D1DCE0E4C2B672DF257145E98A|/
其中p=后面的数值表示了Hashset。每一个文件段Hash值使用一个半角冒号“:”来分隔开。例子中的文件大小为12043984字节(=11.49 MB),也就是说它被分割成两个文件段,一个完整的9.28MB的文件段和一个剩余大小的文件段,各自拥有自己的文件段Hash值。
ICH 智能损坏处理
当eMule完成一个文件段的下载后,它将检查数据是否符合该部分的文件段Hash值。如果正确,则该部分就可以上传来帮助文件传播。
如果错误,则会报告损坏并重新下载该部分。为了避免重新下载整个9.28MB的数据,ICH将重新下载该文件段开头180KB大小的部分,然后再次检查该文件段Hash值是否正确。如果依旧错误,将继续下载接下来的180KB,并再次检查。直到该部分的Hash值正确为止。最理想的情况下,eMule仅需要重新下载这个文件段开头180KB的正确数据。最坏的情况下,如果损坏的部分在文件段的结尾,则整个文件段都会被重新下载。平均来说,ICH在文件段损坏时可以节省50%的重新下载需要。
AICH - 高级智能损坏处理
标准的ICH功能已经非常高效,但是有一个限制是只有整个9.28MB的部分能够被校验,而不是切细。如果不止一个位置出现了损坏,或者一些有害的客户端一次又一次的故意发送一些损坏的数据,甚至伪造整个文件段Hash值,则ICH将不再有效。
而AICH通过更精细的Hash,只需要最小的开销或重新下载的消耗,来照顾到整个数据的完整性。
根Hash,块Hash & AICH Hashset
这一次从9.28MB的文件段开始进行。每一个文件段都被切细成180KB大小的文件块,这样每个文件段可以切分成53个文件块,并且每一个文件块都使用SHA1哈希算法来计算出一个Hash值。这些数值被称作块Hash值,构成了一个完整的AICH Hashset中的最底层。
上图展示了一个包含4个文件段的文件如何构造了一个完整的Hash树。每一个文件段包含了53个文件块总计212个块Hash值,这些一直到根Hash构成了一个7级的Hash树。整个Hash树被称作AICH Hashset。
[Ok3w_NextPage]这些绿色和黄色圆点显示了这些最小的块Hash并直到根Hash之间的数学依赖关系。这意味着如果我们信任根Hash值,那么就可以反过来验证整个Hash树。
eMule可以创建包含根Hash值的链接,例如:
ed2k://|file|name|12043984|6744FC42EDA527B27F0B2F2538728B3E|h=A2NWOTYURUU3P3GCUB6KCNW3FTYYELQB|/
其中h=后面跟着的为根Hash值。对于发布来说提供一个可信的根Hash值可以显著提高文件损坏的修复能力。
恢复损坏的数据
当eMule检测到一个文件段的数据损坏时,会随机向某个客户请求一个包含完整AICH Hash Set的数据恢复包。恢复包里包含了损坏文件段的全部53个块Hash值,以及一个Hash树的校验Hash数量。上图展示了一个包含4个文件段的文件的数据恢复包。校验Hash的数量由文件的文件段计算得来(2^x >= '文件段数量',其中x = 校验Hash的数量)。
在接收到数据恢复包以后,eMule会检查校验Hash来反算可信的根Hash。如果它们匹配,eMule将检查损坏部分的全部53个文件块是否和恢复包里的块Hash值相对应。然后AICH会保存所有匹配它们的块Hash值的文件块,仅仅重新下载损坏的文件块。
在日志中一次成功的数据恢复会显示类似如下的信息:
09.09.2004 02:43:43: 下载的文件段 6 已经损坏:([文件名])
09.09.2004 02:43:46: AICH 成功的恢复了8.22 MB/ 9.28 MB 文件段:6 文件:[文件名]
信任根Hash(Root Hash)
最好是从一个带有根Hash的链接进行下载。并假设链接的来源是可靠的,则此文件的根Hash将被信任一次并保存到磁盘中。
如果链接中没有提供根Hash,则eMule将不得不信任从文件来源那里发送的根Hash值。而且仅会信任至少10个不同来源所发送的相同的根Hash,并且必须有92%的来源都信任这个值。因为这个根Hash是不可靠的,并且仅在当前会话中有效,不会被保存也不会被用来创建带根Hash的链接。
当eMule建立好一个AICH Hashset时,例如当文件下载完成时,它将传播这个根Hash给其他客户。
注意:
新发布的或稀有文件可能没有足够来源来生成一个可信的根Hash。所以强烈建议发布者在发布文件时添加相关的Hash值。
如果没有根Hash或者甚至得到了一个伪造的,eMule在一般情况下同样可以成功下载并完成文件。但此时AICH功能将无法使用。
由于AICH Hashset值非常大,它们不会被载入内存中,但是会被保存到known2.met文件,并仅在需要时读取。
AICH仅仅支持eMule v.44a及以上版本, 但是保留了对旧版客户端的兼容性。