BitTorrent 是一種分發(fā)文件的協(xié)議。它通過URL來識別內(nèi)容,并且可以無縫的和web進(jìn)行交互。它基于HTTP協(xié)議,它的優(yōu)勢是:如果有多個下載者并發(fā)的下載同一個文件,那么,每個下載者也同時為其它下載者上傳文件,這樣,文件源可以支持大量的用戶進(jìn)行下載,而只帶來適當(dāng)?shù)呢?fù)載的增長。(譯注:因為大量的負(fù)載被均衡到整個系統(tǒng)中,所以提供源文件的機(jī)器的負(fù)載只有少量增長)
一個BT文件分布系統(tǒng)由下列實體組成:
一個普通的web服務(wù)器
一個靜態(tài)的“元信息”文件
一個跟蹤(tracker)服務(wù)器
終端用戶的web瀏覽器
終端下載者
理想的情況是多個終端用戶在下載同一個文件。
要提供文件共享,那么一臺主機(jī)需要執(zhí)行以下步驟:
Ø運行一個 tracker服務(wù)器(或者,已經(jīng)有一個tracker服務(wù)器在運行了也可以)
Ø運行一個web服務(wù)器,例如apache,或者已經(jīng)有一個web服務(wù)器在運行了。
Ø在web服務(wù)器上,將文件擴(kuò)展名.torrent 和MIME類型 application/x-bittorrent關(guān)聯(lián)起來(或者已經(jīng)關(guān)聯(lián)了)
Ø根據(jù) tracker服務(wù)器的 URL 和要共享的文件來創(chuàng)建一個“元信息”文件(.torrent)。
Ø將“元信息”文件發(fā)布到web服務(wù)器上
Ø在某個web頁面上,添加一個到“元信息”文件的鏈接。
Ø運行一個已經(jīng)擁有完整文件的下載者(被成為’origin’,或者’seed’,種子)
要開始下載文件,那么終端用戶執(zhí)行以下步驟:
Ø安裝 BT(或者已經(jīng)安裝)
Ø訪問提供 .torrent 文件的web服務(wù)器
Ø點擊到 .torrent 文件的鏈接(譯注:這時候,bt會彈出一個對話框)
Ø選擇要把下載的文件保存到哪里?或者是一次斷點續(xù)傳
Ø等待下載的完成。
Ø結(jié)束bt程序的運行(如果不主動結(jié)束,那么bt會一直為其它人提供文件上傳)
各個部分之間的連通性如下:
網(wǎng)站負(fù)責(zé)提供一個靜態(tài)的文件,而把BT輔助程序(客戶端)放在客戶端機(jī)器上。
Trackers從所有下載者處接收信息,并返回給它們一個隨機(jī)的peers的列表。這種交互是通過HTTP或HTTPS協(xié)議來完成的。
下載者周期性的向tracker登記,使得tracker能了解它們的進(jìn)度;下載者之間通過直接連接進(jìn)行數(shù)據(jù)的上傳和下載。這種連接使用的是 BitTorrent 對等協(xié)議,它基于TCP。
Origin只負(fù)責(zé)上傳,從不下載,因為它已經(jīng)擁有了完整的文件。Origin是必須的。
元文件和tracker的響應(yīng)都采用的是一種簡單、有效、可擴(kuò)展的格式,被稱為bencoding,它可以包含字符串和整數(shù)。由于對不需要的字典關(guān)鍵字可以忽略,所以這種格式具有可擴(kuò)展性,其它選項以后可以方便的加進(jìn)來。
Bencoding格式如下:
對于字符串,首先是一個字符串的長度,然后是冒號,后面跟著實際的字符串,例如:4:spam,就是“ spam”
整數(shù)編碼如下,以 ‘i’ 開始,然后10進(jìn)制的整數(shù)值,最后以’e’結(jié)尾。例如,i3e表示3,I-3e表示-3。整數(shù)沒有大小限制。I-0e是無效的。除了 i0e外,所以以0起始的整數(shù)都無效。I0e當(dāng)然表示0。
列表編碼如下,以’l’開始,接下來是列表值的編碼(也采用bencoded編碼),最后以’e’結(jié)束。例如:l4:spam4:eggse 表示 [‘spam’, ‘eggs’]。
字典編碼如下,以’d’開始,接下來是可選的keys和它對應(yīng)的值,最戶以’e’結(jié)束。例如:d3:cow3:moo4:spam4:eggse,表示{‘cow’:’moo’,’spam’:’eggs’},而d4:spaml1:al:bee 表示 {‘spam’:[‘a(chǎn)’,’b’]}。鍵值必須是字符串,而且已經(jīng)排序(并非是按照字母順序排序,而是根據(jù)原始的字符串進(jìn)行排序)。
元文件是采用bencoded編碼的字典,包括以下關(guān)鍵字:
announce tracker的服務(wù)器
info 它實際上是一個字典,包括以下關(guān)鍵字:
Name:一個字符串,在保存文件的時候,作為一個建議值。僅僅是個建議而已,你可以用別的名字保存文件。
Piece length:為了更好的傳輸,文件被分隔成等長的片斷,除了最后一個片斷以外,這個值就是片斷的大小。片斷大小幾乎一直都是2的冪,最常用的是 256k(BT的前一個版本3.2,用的是1M作為默認(rèn)大小)
Pieces:一個長度為20的整數(shù)倍的字符串。它將再被分隔為20字節(jié)長的字符串,每個子串都是相應(yīng)片斷的hash值。
此外,還有一個length或files的關(guān)鍵字,這兩個關(guān)鍵字只能出現(xiàn)一個。如果是length,那么表示要下載的僅僅是單個文件,如果是files那么要下載的是一個目錄中的多個文件。
如果是單個文件,那么length是該文件的長度。
為了能支持其它關(guān)鍵字,對于多個文件的情況,也把它當(dāng)作一個文件來看,也就是按照文件出現(xiàn)的順序,把每個文件的信息連接起來,形成一個字符串。每個文件的信息實際上也是一個字典,包括以下關(guān)鍵字:
Length:文件長度
Path:子目錄名稱的列表,列表最后一項是文件的實際名稱。(不允許出現(xiàn)列表為空的情況)。
Name:在單文件情況下,name是文件的名稱,而在多文件情況下,name是目錄的名稱。
Tracker查詢。Trakcer通過HTTP的GET命令的參數(shù)來接收信息,而響應(yīng)給對方(也就是下載者)的是經(jīng)過bencoded編碼的消息。注意,盡管當(dāng)前的tracker的實現(xiàn)需要一個web服務(wù)器,它實際上可以運行的更輕便一些,例如,作為apache的一個模塊。
Tracker GET requests have the following keys:
發(fā)送給Tracker的GET請求,包含以下關(guān)鍵字:
Info_hash:元文件中info部分的sha hash,20字節(jié)長。這個字符創(chuàng)幾乎肯定需要被轉(zhuǎn)義(譯注:在URL中,有些字符不能出現(xiàn),必須通過unicode進(jìn)行編碼)
Peer_id:下載者的id,一個20字節(jié)長的字符串。每個下載者在開始一次新的下載之前,需要隨機(jī)創(chuàng)建這個id。這個字符串通常也需要被轉(zhuǎn)義。
Ip:一個可選的參數(shù),給出了peer的ip地址(或者dns名稱?)。通常用在origin身上,如果它和tracker在同一個機(jī)器上。
Port:peer所監(jiān)聽的端口。下載者通常在在 6881 端口上監(jiān)聽,如果該端口被占用,那么會一直嘗試到 6889,如果都被占用,那么就放棄監(jiān)聽。
Uploaded:已經(jīng)上載的數(shù)據(jù)大小,十進(jìn)制表示。
Downloaded:已經(jīng)下載的數(shù)據(jù)大小,十進(jìn)制表示
Left:該peer還有多少數(shù)據(jù)沒有下載完,十進(jìn)制表示。注意,這個值不能根據(jù)文件長度和已下載數(shù)據(jù)大小計算出來,因為很可能是斷點續(xù)傳,如果因為檢查文件完整性失敗而必須重新下載的時候,這也提供了一個機(jī)會。
Event:一個可選的關(guān)鍵字,值是started、compted或者stopped之一(也可以為空,不做處理)。如果不出現(xiàn)該關(guān)鍵字,。在一次下載剛開始的時候,該值被設(shè)置為started,在下載完成之后,設(shè)置為completed。如果下載者停止了下載,那么該值設(shè)置為stopped。
Tracker的響應(yīng)是用bencoded編碼的字典。如果tracker的響應(yīng)中有一個關(guān)鍵字failure reason,那么它對應(yīng)的是一個字符串,用來解釋查詢失敗的原因,其它關(guān)鍵字都不再需要了。否則,它必須有兩個關(guān)鍵字:Interval:下載者在兩次發(fā)送請求之間的時間間隔。Peers:一個字典的列表,每個字典包括以下關(guān)鍵字:Peer id,Ip,Port,分別對應(yīng)peer所選擇的id、ip地址或者dns名稱、端口號。注意,如果某些事件發(fā)生,或者需要更多的peers,那么下載者可能不定期的發(fā)送請求,
(downloader 通過 HTTP 的GET 命令來向 tracker 發(fā)送查詢請求,tracker 響應(yīng)一個peers 的列表)
如果你想對元信息文件或者tracker查詢進(jìn)行擴(kuò)展,那么需要同Bram Cohen協(xié)調(diào),以確保所有的擴(kuò)展都是兼容的。
BT對等協(xié)議基于TCP,它很有效率,并不需要設(shè)置任何socket選項。(譯注:BT對等協(xié)議指的是peer與peer之間交換信息的協(xié)議)
對等的兩個連接是對稱的,消息在兩個方向上同樣的傳遞,數(shù)據(jù)也可以在任何一個方向上流動。
一旦某個peer下載完了一個片斷,并且也檢查了它的完整性,那么它就向它所有的peers宣布它擁有了這個片斷。
連接的任何一端都包含兩比特的狀態(tài)信息:是否choked,是否感興趣。Choking是通知對方,沒有數(shù)據(jù)可以發(fā)送,除非unchoking發(fā)生。Choking的原因以及技術(shù)后文解釋。
一旦一端狀態(tài)變?yōu)閕nterested,而另一端變?yōu)榉莄hoking,那么數(shù)據(jù)傳輸就開始了。(也就是說,一個peer,如果想從它的某個peer那里得到數(shù)據(jù),那么,它首先必須將它兩之間的連接設(shè)置為 interested,其實就是發(fā)一個消息過去,而另一個peer,要檢查它是否應(yīng)該給這個家伙發(fā)送數(shù)據(jù),如果它對這個家伙是 unchoke,那么就可以給它發(fā)數(shù)據(jù),否則還是不能給它數(shù)據(jù))Interested狀態(tài)必須一直被設(shè)置――任何時候。要用點技巧才能比較好的實現(xiàn)這個目的,但它使得下載者能夠立刻知道哪些peers將開始下載。
對等協(xié)議由一個握手開始,后面是循環(huán)的消息流,每個消息的前面,都有一個數(shù)字來表示消息的長度。握手的過程首先是先發(fā)送19,然后發(fā)送“BitTorrent protocol”。19就是“BitTorrent protocol”的長度。
后續(xù)的所有的整數(shù),都采用big-endian 來編碼為4個字節(jié)
在協(xié)議名稱之后,是8個保留的字節(jié),這些字節(jié)當(dāng)前都設(shè)置為0。
接下來對元文件中的 info 信息,通過 sha1 計算后得到的 hash值,20個字節(jié)長。接收消息方,也會對 info 進(jìn)行一個 hash 運算,如果這兩個結(jié)果不一樣,那么說明對方要的文件,并不是自己所要提供的,所以切斷連接。
接下來是20個字節(jié)的 peer id。
這就是握手過程
接下來就是以消息長度開始的消息流,這是可選的。長度為0 的消息,用于保持連接的活動狀態(tài),被忽略。通常每隔2分鐘發(fā)送一個這樣的消息。
其它類型的消息,都有一個字節(jié)長的消息類型,可能的值如下:
‘choke’, ‘unchoe’, ‘interested’, not interested’類型的消息不再含有其它數(shù)據(jù)了。
‘bitfield’永遠(yuǎn)也僅僅是第一個被發(fā)送的消息。它的數(shù)據(jù)實際是一個位圖,如果downloader已經(jīng)發(fā)送了某個片斷,那么對應(yīng)的位置1,否則置0。Downloaders如果一個片斷也沒有,可以忽略這個消息。(通過這個消息,能知道什么了?)
‘have’類型的消息,后面的數(shù)據(jù)是一個簡單的數(shù)字,它是下載者剛剛下載完并檢查過完整性的片斷的索引。(由此,可以看到,peer通過這種消息,很快就相互了解了誰都有什么片斷)
‘request’類型的消息,后面包含索引、開始位置和長度)長度是2的冪。當(dāng)前的實現(xiàn)都用的是215 ,而關(guān)閉連接的時候,請求一個超過2 17的長度。(這種類型的消息,就是當(dāng)一個peer希望另一個peer給它提供片斷的時候,發(fā)出的請求)
‘cancel’類型的消息,它的數(shù)據(jù)和’request’消息一樣。它們通常只在下載趨向完成的時候發(fā)送,也就是在‘結(jié)束模式“階段發(fā)送。在一次下載接近完成的時候,最后的幾個片斷需要很長時間才能下載完。為了確保最后幾個片斷盡快下載完,它向所有的peers發(fā)送下載請求。為了保證這不帶來可怕的低效,一旦某個片斷下載完成,它就其它peers發(fā)送’cancel’消息。(意思就是說,我不要這個片斷了,你要是準(zhǔn)備好了,也不用給我發(fā)了,可以想象,如果對方還是把數(shù)據(jù)發(fā)送過來了,那么這邊必須忽略這些重復(fù)的數(shù)據(jù))。
‘piece’類型的消息,后面保護(hù)索引號、開始位置和實際的數(shù)據(jù)。注意,這種類型的消息和 ‘request’消息之間有潛在的聯(lián)系(譯注:因為通常有了request消息之后,才會響應(yīng)‘piece’消息)。如果choke和unchoke消息發(fā)送的過于迅速,或者,傳輸速度變的很慢,那么可能會讀到一些并不是所期望的片斷。