天天看點

BT源代碼學習心得(四):種子檔案的生成

BT源代碼學習心得(四):種子檔案的生成

發信人: wolfenstein (NeverSayNever), 個人文集

标  題: BT源代碼學習心得(四):種子檔案的生成

發信站: 水木社群 (Wed Aug  3 22:22:09 2005), 文集 (本文包含HTML标記,終端模式下可能無法正确浏覽)

    在知道種子檔案采取的編碼方式後,我們現在可以來看一個種子檔案具體是如何生成的

了。在BT中,生成種子檔案的可執行子產品是btmaketorrent.py(指令行模式)或者

btmaketorrentgui.py(圖形界面模式),通過分析,可以知道它們最終都将調用函數

make_meta_files進行種子檔案的生成,差別僅僅在于提供給這個函數的參數從何而來。命

令行模式下的程式很簡單,即直接從指令行下擷取參數,GUI部分的程式以後再和下載下傳客戶

端的圖形界面程式一起分析,現在我們先直接切入正題。

    BitTorrent/makemetafile.py子產品中提供函數make_meta_files。它的參數意義如下:

    URL:Tracker的URL位址,在BT的協定設計中,還是需要有個伺服器作為tracker來協調

各個用戶端的下載下傳的,tracker部分的程式以後會介紹,現在隻需要知道這個URL将要作為一

條資訊寫入到種子檔案中即可。

    file:種子檔案的來源檔案或目錄清單(即準備要在BT上共享的資源),注意,這裡的列

表意思是該清單中的每一項都為其生成一個種子檔案,而此清單中的每一項可以是一個檔案

或者是一個目錄。

    flag:一個Event對象,可以用來檢查是否使用者要求中止程式。程式設計得比較合理,

可以在很細的粒度下檢查這個Event是否被觸發,如果是則中止執行。

    progressfunc:一個回調函數,程式會在恰當的地方調用它,以表示現在的工作進度,

在指令行模式下,這個回調函數被指向在控制台上顯示進度資訊的函數,在GUI模式下,這

個回調函數則會影響一個圖形界面的進度條。    filefunc:也是一個回調函數,程式會在恰當的地方調用它,以表示現在在處理哪個文

件。

    piece_len_pow2:分塊的大小,BT中把要共享的資源分成固定大小的塊,以便處理。這

個參數就是用2的指數表示的塊的大小,例如當該參數為19的情況下,則表示共享的資源将

被分成512k大小的塊為機關進行處理。

    target:目标檔案位址,即種子檔案的位址。這個參數可以不指定(None),則種子檔案

将與公享資源處于同一目錄。

    comment:說明。一段可以附加在種子檔案内的資訊。

    filesystem_encoding:檔案系統編碼資訊。

    make_meta_files的主要工作是進行一系列的檢查。例如在開始的時候就檢查files的長

度(元素的個數)和target,當files的長度大于1且target不是None的時候就會報錯,因為如

果要生成多個種子檔案的話,是不能指定target的(這樣target隻确定了一個種子檔案的保

存位置)。接下來檢查檔案系統的編碼問題。然後把files中所有以.torrent結尾的項目全部

刨掉,剩下的作為參數傳遞給make_meta_file進行處理,注意,這個函數一次生成一個種子

檔案。

    下面來看make_meta_file,它一開始計算出塊的大小,以2的指數為基礎。接下來找到

種子檔案的儲存位址,如果有target,以target為準,否則如果要對一個目錄生成種子檔案

,則生成以那個目錄名為名稱,字尾".torrent"的檔案。否則生成以源檔案為名稱,字尾

".torrent"的檔案。

    下面調用函數makeinfo來生成一個"info"。這個info是什麼東西呢?繼續看。

makeinfo首先檢查傳給它的path,看看是單個檔案還是一個目錄。如果是一個目錄的話,則

調用subfiles把這個目錄下的所有檔案全部列出來,這個subfiles設計得比較巧妙,使用堆 棧的方法避免了遞歸調用。從subfiles得到結果後,首先對它們進行排序。然後使用變量

fs儲存這些檔案的清單資訊,fs是一個list結構,每個元素包含了檔案名稱和它的大小組成

的二進制組。接下來就是記錄檔案的内容了,下面的這個算法看上去有點暈,其實它的意義是

很明确的,每次從要共享的資源裡讀取長度為piece_length(就是前面那個以2的指數為基礎

計算出來的塊的大小)的資料,然後計算它的sha消息摘要值。如何做到這一點呢?就是根據

那個排好序的檔案清單,讀出piece_length的長度的内容,如果這個檔案長度不夠,則再讀

下一個檔案,知道長度夠了或者讀完所有檔案為止。生成一個消息摘要後把它加入到

pieces數組中,再讀下一塊,直到全部處理完。為一個檔案生成info的方法類似,隻是更簡

單,直接從這個檔案中一塊一塊得處理即可。最後這個makeinfo傳回的info是一個字典,它

的資料如下:

    pieces:每一塊的消息摘要值的連接配接。

    piece length:每一塊的長度。

    files:檔案的清單資訊,這裡由于檔案順序和生成消息摘要的順序是相同的,以後BT

的用戶端根據種子檔案的描述,就可以很清晰得确定原始的檔案名和它們的大小,再配以消

息摘要值,就可以檢查下載下傳内容是否正确了。

    name:種子檔案的内部名稱,種子檔案可以被随便改名,但是為了識别它友善,内部還

是起了這麼一個名稱的,通常用要共享的資源來命名它。

    我們注意到flag.isSet多處被檢查,其中粒度最小的地方是在讀取了一塊之後。它傳回

後将一路傳回到make_meta_files結束,這樣使用者随時可以中斷程式的執行。

    在makeinfo傳回info這個字典類型的資料後,再調用check_info這個函數對其内容進行

檢查,這個函數定義在BitTorrent/btformats.py子產品中,後面在用戶端進行下載下傳的時候還

需要檢查它。    最後我們看到的是一個類型為字典的data,其中的元素包含了announce,一個字元串,

creation date,一個整型資料,info,又是一個字典,如果有comment的話,那麼還包含了

字元串類型的comment。

    最後把這個類型為字典的data儲存到磁盤上,工作就算完成了。怎麼對這種比較複雜的

資料類型進行編碼以友善儲存呢?就是上次提到的bencode。

    是以我們可以看到,一個種子檔案就是一個類型為字典的data編碼後的情形。  

繼續閱讀