?? emule源代碼解析-1.txt
字號:
pnglib:
http://www.libpng.org/pub/png/libpng.html
下載它們,解壓它們,編譯它們。編譯的時候注意要和eMule的工程的參數一致:字符集為Unicode,支持多線程安全,調試版或者是發行版可以根據需要選擇,但是也要和eMule的工程參數一致。這些庫的解壓包里通常都能找到VC的工程文件,但是版本低一些,直接轉化就可以了。另外建議編譯這些庫的時候都選擇生成靜態庫,不要生成動態的庫,這樣最后生成的可執行文件就可以自己運行了。編譯完這些庫,包括從其它地方下載的和eMule自帶的id3lib庫和CxImage庫后,就可以開始編譯emule了。而編譯emule也無非就是注意讓它能夠在編譯的時候找到所有的頭文件,以及在鏈接的時候能夠找到所有的庫。在鏈接的時候能夠找到所有的庫可以通過修改工程文件里面的屬性 ->配置屬性 ->鏈接器 ->輸入->附加依賴項來完成。但是能夠找到所有的頭文件反而需要一些技巧了。由于emule的代碼中對于這些庫的頭文件的包含,在一定程度上限定了那些庫的路徑和emule的工程的路徑的相對位置,因此需要把那些解壓過的庫的目錄移到一些合適的地方,有時還需要給這些目錄改個名稱。
eMule中要讀取的配置文件數量較多,每種配置文件都是自己定義的格式,為了方便讀取和存儲這些文件,eMule中有一個很重要的基礎設施類來復制這些文件操作,它能夠很方便得處理一些常用數據類型的讀寫,并且帶有一定的安全保護機制。這項基礎設施在SafeFile.cpp和SafeFile.h中實現。在kademlia\io目錄下有這項功能的另外一項實現。它們實現的功能基本上相似,但是kademlia\io目錄下的版本實現的時候多了一個以Tag作為單位進行讀寫的功能。這些實現中和另外一項基礎設施,那就是字符串轉化密切相關。StringConversion.cpp和StringConversion.h是eMule中專門復制各類字符串轉化的基礎設施,什么Unicode啊,多字節流啊,或者是UTF-8之類的,在這里轉化全部都不是問題。關于字符串轉化,個人推薦盡量使用Unicode的寬字符,這樣可以最大程度得避免亂碼。
SafeFile.cpp或者kademlia\io目錄下的實現都有這樣的特點,那就是把數據操作的行為和數據操作的對象分割開來。它們都定義了一個抽象的數據操作的基類(在SafeFile.cpp中是CFileDataIO,在kademlia目錄下是DataIO.cpp實現的Kademlia::CDataIO),這個類中只負責實現在邏輯上操作一項數據的行為,例如,要讀取出一個32位的整型,那么就是讀出四個字節到一個整型數值的地址中,要讀取或者寫入其它類型的數據用的是類似的方法。但是這個類把物理上進行數據操作的方法全部都聲明為純虛函數,即讀出多少個字節,寫入多少個字節這樣的。有了這樣一個基類,就可以非常方便得在它上面進行重載,把這些純虛函數定義為向某塊內存中進行讀寫的操作,就能很方便得將較為復雜的數據序列化到一塊連續的內存,而如果這些純虛函數是向文件讀寫的操作,那么自然就可以很方便得用來讀寫各種格式比較奇怪的自己定義的配置文件了。
這些類要讀取的數據對象通常有這些,各種整型,字符串,以及Tag類型。整型讀寫起來比較簡單,從1個字節的,2個字節的到4個,8個或者16個字節類型的數據讀寫方法都比較類似。這里要稍微提一下16個字節的那種,16個字節是128位,是eMule中的Kad網的隨機生成的ID的長度,也是eMule中常用的MD4的hash算法生成的結果的長度。通常用來直接存取整個的這樣的一個ID。在kademlia\utils目錄下的UInt128.cpp實現了一個表示128位的整數的類,功能十分完善,可以進行一些算術操作,并且可以進行比較,這樣為它以后作為key出現在hash表中打下了基礎。仔細學習UInt128.cpp中的代碼實現可以學到很多在編寫這種自定義的數據對象類型時應該注意的問題。
數據操作中另外一項很重要的操作是字符串,總的原則是先寫一個長度,再寫內容。但是到具體的操作的時候就需要注意這些細節了,如長度是寫4個字節還是兩個字節,字符串的內容要不要用UTF-8進行編碼。這些操作就需要和StringConversion.cpp緊密合作了。其實后者的字符串轉化函數很多也是調用ATL的相關函數,只是在外面再包上一層MFC的CString。
在kademlia\io\DataIO.cpp中實現的CDataIO中,還另外實現了按照Tag進行讀寫的功能。這在網絡上交換共享文件的元信息非常重要,通常一個文件的元信息就可以分解成很多的Tag,如"文件名=xxx","文件長度=xxx"等等。也就是說,一個Tag就是表示某項屬性等于某個值這樣一個事實。在Opcodes.h這個文件中定義了很多的代碼,其中就有很多常見的Tag的屬性名稱。CDataIO類中存儲Tag的屬性名都是先存一個字節的類型,再存名稱,最后按照類型存值。
eMule中的這幾項基礎設施都是編寫得比較好的,可以很方便得拿出來復用。像字符串編碼的處理和具有一定數據結構的文件IO操作在很多地方都會很有用。eMule中這些類的實現基本上復制到其它的工程文件中只要稍微修改一下很快就能使用。以后我們還將看到eMule中很多其它很有用的基礎設施。
emule作為一個文件共享方面的程序,首先要對自己共享的所有的文件的信息都十分清楚,類CKnownFileList的作用就是這樣的,它在emule.cpp中隨著cmuleapp類創建的時候被創建。
CKnownFileList類使用了MFC的CMap類來維護內部的hash表,這也可以看出emule和MFC的關系確實非常緊密。這里如果用STL的map其實也是可以的。它內部維護了一個已知的文件的列表和取消了的文件列表。這些hash表的關鍵字都是文件的hash值。這樣能夠判斷出文件名不同而內容相同的文件,而一般要讓不同內容的文件有相同的hash值是非常困難的,這也是hash函數它設計的初衷。因此除非是碰上王小云教授這樣的牛人,我們基本上可以認為,兩個文件hash值相同就代表了它們內容相同。再來看CKnownFileList.cpp,這個文件其實并不長,因為管理一個列表確實不需要太多種類的操作,如果對于每個具體的文件有一個很強大的類來處理它的話。而這里確實有,它就是CKnownFile。有了這么一個類,我們就可以看到,CKnownFileList類所需要做的工作就是能夠根據一些信息查找到對應的CKnownFile類,能夠復制其它的列表中的信息,能夠把所有的這些信息存成文件,然后下次emule運行的時候能夠把這些信息快速恢復出來,最重要的是能夠在完成以上工作的情況下不造成內存泄漏。
CKnownFile類就是一個專門關注某個特定文件的信息的類,它仍然有其基類CAbstractFile。但是它和CAbstractFile類的主要區別就是CAbstractFile類只有基本的信息存取的功能,而CKnownFile能夠主動的生成這些信息,例如,給一個文件的路徑給CKnownFile,它能夠主動地去獲取和這個文件有關的一切信息,并且把它保存在自己的成員變量里(CreateFromFile)。CKnownFile.cpp文件看上去比較長,是因為它做的工作比較多,現在版本的emule中,除了對某個文件進行全文hash以外,還采用了BT的方式,進行分塊hash,這樣在傳輸文件的時候,即使發生出錯的情況,也可以不必重傳整個文件,而只是重傳有錯誤的那塊,這種機制叫做高級智能損壞處理(AICH,Advanced Intelligent Corruption Handling),這個機制以后再繼續分析。
CKnownFile把讀到的文件信息都保存成一個一個的Tag。它在運行中會盡量得獲取更多的文件信息,例如,對于媒體類型的文件,它能夠調用id3lib庫來獲取諸如作者,唱片發行年代,風格等tag信息。如果是視頻媒體文件,它還會去抓圖(功能實現:CFrameGrabThread)。
CKnownFile還能夠隨時掌握目前該文件的下載情況(內部有個CUpDownClient的列表),當然,還會根據要求序列化和反序列化自己,LoadFromFile和WriteToFile都以CFileDataIO為參數,這樣方便CKnownFileList保存和讀取它的列表中的所有文件的信息。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -