與peer創建tcp鏈接後,首先發送handshake消息進行握手python
handshake消息格式以下:多線程
一個字節0x19 + 一個字符串'BitTorrent protocol' + 8 byte 保留字節默認值爲0(draft中對保留字節有定義)異步
+ 種子文件中info 部分的sha1字,大小爲20個字節 + 20個本身的peer id(從tracker獲取到的peer信息大多沒有peerid,這個可使用本地的peer id)socket
若是handshake信息協商不上,tcp鏈接將被關閉。tcp
BT標準BEP-3中定義了8種peer消息:消息格式爲msg_len(4個字節) + msg_type(1一個字節) + payload函數
0 - choke --發送該消息表示本段發送阻塞,對端將不能獲取到piece數據,payload 爲 0性能
1 - unchoke --發送該消息表示解阻塞,對端能夠開始發送請求獲取piece數據,payload 爲 0線程
2 - interested --發送該消息,表示對對端的pieces數據有興趣,payload 爲 0設計
3 - not interested ---發送該消息,表示對對端的pieces數據沒有興趣了,payload 爲 0rest
4 - have ---發送該消息,通告對端 本段擁有的pieces,payload爲4個字節的piece index
5 - bitfield ---發送該消息,通告對端 本段擁有的pieces,爲bit map的方式表示每一個piece index在本端是否擁有。piece index所在bit位爲1,表示擁有。
該消息爲handshake成功後的第一個消息。
6 - request ---piece請求消息,payload爲: index, begin, and length,都是4個字節表示,length通常實現爲0x8000, 最大不能超過0x20000。
7 - piece ---piece 數據,payload爲: index, begin,data
8 - cancel ---發送該消息,表示本端取消了某個piece請求。payload爲:index, begin, and length
使用python的異步socket接口實現,爲了減小處理過程被socket阻塞,使用多個線程處理每一個peer。
每一個peer包括3個線程:request timeout timer ,socket send data thread, socket receive data thread,使用select 函數判斷socket是否可讀、可寫。
對socket讀寫操做時使用RLock進行保護,select阻塞進程時不加鎖,避免阻塞其餘線程。
發送數據數據時先寫一個隊列,而後經過set threading.Event 變量出發socket send data thread發送數據,保證發送數據的線程不阻塞
因爲 python沒有結束線程的接口,socket send data thread, socket receive data thread 須要依賴特殊變量的賦值,使socket處理進程結束。
使用同步調用來觸發下載過程運轉,儘可能不使用timer輪詢的方式,能夠下降cpu使用率並加快下載過程。
可是,多線程間的同步調用因爲鎖的存在,會致使性能降低並容易引入信號量死鎖的問題。須要仔細設計好多線程的運行軌跡避免死鎖。
draft BEP中定義的功能暫未實現,peer的上傳流控未實現,peer質量分級未實現。