B編碼以及BT種子文件分析


    去年年末的時候,有個朋友說要做一個BT協議的上傳和下載,要俺幫忙,於是在那個時候搜尋了各種關於種子文件的文件格式資料。順便整了一個BT格式的分析類庫出來。目前,貌似朋友那便沒說要繼續整BT協議的上傳和下載了,估計大概換了協議吧,呵呵。所以這個放在手里也用處不大了,剛好又很久沒寫博了,這個就作為當年的第一篇開篇博客吧。言歸正傳,正文開始

   說到BT的種子文件格式,首先我們必須要了解的就是Bencoding編碼格式。關於這個格式的定義,基本上還是比較簡明的,B編碼總共只支持4種類型,既整數,字符串,列表和字典。整數以i標記開頭以e標記結尾,中間是整數數字,字符串以:標記開頭然后根接字符串的長度,最后是字符串內容,列表以l標記開頭,以e結尾,字典以d開頭以e結尾。列表可以包含任何的BT元素,字典也可以包含任何的BT元素,不過字典的Key必須是字符串。如此以來分析,整數和字符串是兩種單元的元素,可以很好的解析,基本上不用分析就能搞定,而列表和字典,則就需要根據給定的字符串進行分析處理了,這個分析實際上也簡單,先碰到開頭的標記,然后不斷的往下判斷讀取,碰到結尾標記e結束,如果在碰到結尾標記之前還又碰到其他的標記,則可進行遞歸處理,所以,處理起來也方便了。

    B編碼解析完成,那么BT種子文件的處理也就簡單了。BT種子文件實際上就是由B編碼的字典組成,其內部的字典鍵介紹,可以參考相關資料,這里我摘錄一些如下:

Torrent文件內的數據結構分為以下幾部分:

announce:Tracker的主服務器

announce-list:Tracker服務器列表

comment:種子文件的注釋

comment.utf-8:種子文件注釋的utf-8編碼

creation date:種子文件建立的時間,是從1970年1月1日00:00:00到現在的秒數。

encoding:種子文件的默認編碼,比如GB2312,Big5,utf-8等

info:所有關於下載的文件的信息都在這個字段里,它包括多個子字段,而且根據下載的是單個文件還是多個文件,子字段的項目會不同。

當種子里包含多個文件時,info字段包括如下子字段:

files:表示文件的名字,大小,該字段包含如下三個子字段:

        lenghth:文件的大小,用byte計算

         path:文件的名字,在下載時不可更改

          path.utf-8:文件名的UTF-8編碼,同上


以上的三個字段每個文件都有一組值。

name:推薦的文件夾名,此項可於下載時更改。

name.utf-8:推薦的文件夾名的utf-8編碼,同上。

piece length:每個文件塊的大小,用Byte計算

pieces:文件的特征信息,該字段比較大,實際上是種子內包含所有的文件段的SHA1的校驗值的連接,即將所有文件按照piece length的字節大小分成塊,每塊計算一個SHA1值,然后將這些值連接起來就形成了pieces字段,由於SHA1的校驗值為20Byte,所以該字段的大小始終為20的整數倍字節。該字段是Torrent文件中體積最大的部分,可見如果大文件分塊很小,會造成Torrent文件體積龐大。

publisher:文件發布者的名字

publisher.utf-8:文件發布者的名字的utf-8編碼

publisher-url:文件發布者的網址

publisher-url.utf-8:文件發布者網址的utf-8編碼。

另外,當發布單文件時,files字段是沒有的,而


lenghth:
name:
name.utf-8:


這三個字段負責描述單文件的屬性:大小,名字,名字的utf-8編碼。其他項目和多文件相同。

以上的項目即為info字段的全部。

說到info就不得不說
INFO_HASH,這個值是info字段的HASH值,20個Byte,同樣是使用SHA1作為HASH函數。由於info字段是發布的文件信息構成的,所以INFO_HASHBT協議中是用來識別不同的種子文件的。基本上每個種子文件的INFO_HASH都是不同的(至少現在還沒有人發現有SHA的沖突),所以BT服務器以及客戶端都是以這個值來識別不同的種子文件的。

計算的具體范圍是從info字段開始(不包含"info"這四個字節),一直到nodes字段為止(不包含"nodes"這5個字節和nodes前邊表示nodes字段長度的"5:"這兩個字節)。另外,
INFO_HASH值是即時計算的,並不包含在Torrent文件中。

nodes:最后的一個字段是nodes字段,這個字段包含一系列ip和相應端口的列表,是用於連接DHT初始node。

綜上,多文件Torrent的結構的樹形圖為:

Multi-file Torrent
├─announce
├─announce-list
├─comment
├─comment.utf-8
├─creation date
├─encoding
├─info
│ ├─files
│ │ ├─length
│ │ ├─path
│ │ └─path.utf-8
│ ├─name
│ ├─name.utf-8
│ ├─piece length
│ ├─pieces
│ ├─publisher
│ ├─publisher-url
│ ├─publisher-url.utf-8
│ └─publisher.utf-8
└─nodes

單文件Torrent的結構的樹形圖為:

Single-File Torrent
├─announce
├─announce-list
├─comment
├─comment.utf-8
├─creation date
├─encoding
├─info
│ ├─length
│ ├─name
│ ├─name.utf-8
│ ├─piece length
│ ├─pieces
│ ├─publisher
│ ├─publisher-url
│ ├─publisher-url.utf-8
│ └─publisher.utf-8
└─nodes


BT類庫文件簡碼:

//B編碼支持的數據類型
TDxBenValueTypes = (DBV_String,DBV_Int,DBV_List,DBV_Dictionary);
//B編碼的節點,類似於JSON節點,
TDxBenValue = class
private
FParent: TDxBenValue;
protected
function GetType:TDxBenValueTypes; virtual; abstract;
procedure Parser(str: string);virtual;abstract;
function GetAsInteger: Integer;virtual;abstract;
function GetAsString: string;virtual;abstract;
function GetObject: TDxBenValue;virtual;
public
constructor Create;overload;virtual;
constructor Create(str: string);overload;virtual;
property ValueType: TDxBenValueTypes read GetType;
function ToString: string;override;
property Parent: TDxBenValue read FParent;
property AsInteger: Integer read GetAsInteger;
property AsString: string read GetAsString;
property AsValueObject: TDxBenValue read GetObject;
end;

TDxBenInt = class(TDxBenValue)
private
FValue: Integer;
protected
function GetType:TDxBenValueTypes;override;
function GetAsInteger: Integer;override;
procedure Parser(str: string);override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
public
constructor Create;override;
function ToString: string;override;
end;

TDxBenString = class(TDxBenValue)
private
FValue: string;
protected
function GetType:TDxBenValueTypes;override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
function GetAsInteger: Integer;override;
procedure Parser(str: string);override;
public
function ToString: string;override;
end;

TDxBenDictionary = class;
TDxBenList = class(TDxBenValue)
private
FList: TList;
function GetCount: Integer;
function GetValues(index: Integer): TDxBenValue;
protected
procedure Parser(str: string);override;
procedure ParserToList(var P: Pchar;List: TDxBenList);
procedure ParserToDictionary(var p: PChar;Dict: TDxBenDictionary);
function GetType:TDxBenValueTypes;override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
function GetAsInteger: Integer;override;
public
procedure Clear;
constructor Create; override;
constructor CreateFromString(str: string);
destructor Destroy;override;
function ToString: string;override;
property Count: Integer read GetCount;
property Values[index: Integer]: TDxBenValue read GetValues;
end;

TDxBenDictionary = class(TDxBenValue)
private
FDict: TDictionary<string,TDxBenValue>;
function GetCount: Integer;
function GetValues(Key: string): TDxBenValue;
protected
procedure ParserToList(var P: Pchar;List: TDxBenList);
procedure ParserToDictionary(var p: PChar;Dict: TDxBenDictionary);

procedure Parser(str: string);override;
function GetType:TDxBenValueTypes;override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
function GetAsInteger: Integer;override;
public
procedure Clear;
constructor Create;override;
destructor Destroy;override;
function ToString: string;override;
property Count: Integer read GetCount;
property Values[Key: string]: TDxBenValue read GetValues;
end;

TDxBtInfo = class(TDxBenDictionary)
private
function GetSingleFile: Boolean;
function GetFiles: TDxBenList;
function GetName: string;
function GetNameUtf8: string;
function Getpublisher: string;
function GetpublisherUtf8: string;
function Getpublisherurl: string;
function GetpublisherurlUtf8: string;
public
property SingleFile: Boolean read GetSingleFile;
property Files: TDxBenList read GetFiles;
property Name: string read GetName;
property NameUtf8: string read GetNameUtf8;
property publisher: string read Getpublisher;
property publisherUtf8: string read GetpublisherUtf8;
property publisherurl: string read Getpublisherurl;
property publisherurlUtf8: string read GetpublisherurlUtf8;
end;

TDxTorrentFile = class
private
FDict: TDxBenDictionary;
procedure ParserStream(Stream: TStream;Dict: TDxBenDictionary);overload;
procedure ParserStreamToList(Stream: TStream; List: TDxBenList);
function GetComment: string;
function GetEncoding: string;
function GetCreator: string;
function Getannounce: string;
function Getannounce_list: TDxBenList;
function GetBtInfo: TDxBtInfo;
function GetCreateDate: TDateTime;
public
procedure Clear;
constructor Create;
destructor Destroy;override;
procedure LoadFromFile(FileName: string);
procedure LoadFromStream(Stream: TStream);
property Comment: string read GetComment;
property Encoding: string read GetEncoding;
property Creator: string read GetCreator;
property announce: string read Getannounce;
property announce_list: TDxBenList read Getannounce_list;
property BtInfo: TDxBtInfo read GetBtInfo;
property CreateDate: TDateTime read GetCreateDate;
end;
implementation
end.

在CSDN上,貌似也有一個C版本的解析,不知道他的解析方式是否和我的類似,相關朋友可以一並下載了看看

完整代碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM