BT原始碼學習心得(十四):用戶端原始碼分析(對等客戶串連中的阻塞管理)

來源:互聯網
上載者:User
 

BT原始碼學習心得(十四):用戶端原始碼分析(對等客戶串連中的阻塞管理)Author: wolfenstein從上一次我們的分析可以看出當對等客戶建立串連後,通過握手協議交換資訊,這樣對於每個串連都有一個Connection對象,然後有一個SingleDownload和Upload與其對應。這一次將從握手協議完成後繼續分析,然後介紹Choker,阻塞策略控制器的工作原理。SingleDownload在初始化時沒有做什麼特殊的操作,僅僅是建立了一個BadDataGuard對象和它對應。這個對象是用來統計壞資料的資訊,以便確定壞的對等客戶的。而Upload對象在建立的時候,如果自己已經有部分下載資料,就把自己的塊擁有情況發送出去(send_bitfield)。現在就可以來看send_bitfield,我們可以看到在Connection中定義了不少send_xxx函數用來發送某種訊息,並且在Connection對象定義之前,定義了那些訊息的類型的對應的常數項。另外這些send_xxx函數大都調用了_send_message,它的作用就是在要發送的訊息前面添加上它的長度(4個位元組),然後發送出去,如果有必要,則放入隊列中稍後發送。這樣,每一次_got_message得到的就是訊息的內容了。現在來看_got_message,它直接取第一個位元組就行了,這就是訊息的類型。以後我們可以再檢查其它類型的訊息,現在我們直接看elift==BITFIELD這部分,得到對方的塊擁有狀況位元數組後,讓自己的download對象記錄下來,即調用SingleDownload.got_have_bitfield()。這個函數首先檢查自己是否下載完成,然後檢查對方的位元數組中"假"值的個數,如果自己下載完成了且對方的位元數組中"假"值為0,則說明對方也下載完成了,而兩個都在做種的對等客戶之間的串連是沒有意義的,可以關閉它。然後self.have=have這一句記錄下對方的塊擁有情況。所以前面提到StorageWrapper儲存自己的塊擁有狀況,而對應於每個Connection對象的SingleDownload對象中則保留了對方的塊擁有狀況。然後讓PiecePicker記錄下別人有一塊(got_have,complete記錄的是自己有一塊,在_SingleTorrent的代碼中可以看到)。下面的這個endgame則是一種策略模式,即表示進入收尾階段,它檢查自己所有的網路請求all_requests(後面還會分析到它),如果對方有某一塊(再次注意,這裡self.have[piece]是對方有第piece塊,而不是自己),那麼發送一條訊息,send_interested()。表示說我對你(所擁有的內容)感興趣。而如果沒有進入收尾階段,則只是檢查自己有那塊沒有而對方有,如果有的話,則send_interested()。注意send_interested()調用一次,對方知道這個意思就行了。看Connection._got_message中得到這個訊息後怎麼處理。是self.upload.got_interested()。這個函數中維持自己的interested變數為真值,然後通知choker這件事情,choker.interested則選擇是否要進行一次_rechoke()。現在應該注意到choked和interested這兩個變數,這兩個變數的值的意義分別是是否阻塞和是否感興趣,它們對下載起到直接開關的作用。在每個SingleDownload和Upload對象中都有這兩個變數。在初始化時,choked都為真而interested都為假,這樣就不會有實際的內容(即種子檔案的共用資源)在流通,而要有實際的內容流通必須這兩個變數的值和它們初始化時的值剛好相反才行,也就是說,只有當一方對另外一方感興趣,而對方又沒有拒絕你(choked=false)的時候,你們之間在這個方向才可能會存在實際的下載流量。另外這兩個變數在網路連接的每個方向都是保持一致的,即Upload中的這兩個變數和串連另外一頭的SingleDownload中的這兩個變數保持一致,如果有某個變數發生變化,要發送訊息給對方,讓對方能繼續保持一致。注意這裡的保持一致指的是網路連接的兩頭,而不是本地的Connection對象對應的SingleDownload和Upload,即本地的Connection的SingleDownload和對等客戶的Upload保持一致,而本地的Connection的Upload和對等客戶的SingleDownload保持一致,而在同一個串連中,下載和上傳的兩個方向有可能不一致,即一個方向阻塞了,另一個方向還在下載。前面已經注意到,interested這個變數的改變很容易,只要發現對方有自己沒有的塊,就會發送這條訊息,而choked這個變數的控制就有一定的策略了。Choker就控制所有的串連(_SingleTorrent層級)的阻塞。它在初始化時即保證_round_robin每十秒種執行一次,而每次有串連進入時,用connection_made來進行登記,Choker中維護了所有串連的列表,且這個列表是故意打亂順序的。在BT的控制策略中,我們還可以多次看到隨機打亂順序的情況發生,因為有時隨機數就是最好的策略。在_round_robin中,首先檢查是否已經完成,如果完成則調用_rechoke_seed(),按照自己已經開始做種的情況進行處理。而計算count%3的餘數就可以保證_round_robin執行三次這部分代碼會執行一次,因為count只有在_round_robin中會被加一。這部分代碼就是選擇一個choked和interested同時為真的串連放到列表的開頭(不要讓喜歡你的人等待太久)。在_rechoke()中,首先選擇出一些符合解除choked狀態的串連(條件是interested和下載方向的is_snubbed,即目前時間是否距離上次下載到東西的時間過短),然後把所有的這些串連按照下載的速度排序,由於前面增加了一個負號,因此下載速度最塊的排在前面。然後根據配置項中的最大上傳數計算一個配額,這個配額不能等於最大上傳數,最多隻能對於這個數減一,從這個列表中取出排名前面的若干位,設定一個mask標誌。下面計算出最小上傳數,count。count至少要為一,如果最小上傳數比前面的配額還大,那麼count也相應增大。下面就是解除choke狀態了,首先mask為1的,無條件解除,如果mask不為1,但是count還大於0,那麼用掉一個count,解除choke狀態,其它的串連,一律choke掉。Upload的choke和unchoke都是在確定狀態改變的情況下,開始向對方通知這一訊息。這一次結合串連中開始的部分訊息互動過程,介紹了choker這一阻塞策略管理器的工作原理。下一次將開始介紹在串連的雙方的已經同意交換資料(choked為假而interested為真)時的情況。 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.