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。
這些綠色和黃色圓點顯示了這些最小的塊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及以上版本, 但是保留了對舊版用戶端的相容性。