BitTorrent 協議規範(BT協議集合)十一

2021-04-12 12:59:26 字數 2901 閱讀 7084

tracker伺服器原始碼分析之三:httphandler 類

本篇文章分析 httphandler類,它在 httphandler.py 檔案中。

external_connection_made():在建立新的連線的時候被呼叫

data_came_in():連線上有資料可讀的時候被呼叫

connection_flushed():當在某個連線上傳送完資料之後被呼叫

httphandler 就是這樣乙個 handler 類,它具備以上介面。

httphandler **很少,因為它把主要工作又交給 httpconnection 了。

我們看 httphandler 類的這幾個函式:

l       external_connection_made():

每當新來乙個連線的時候,就建立乙個 httpconnection 類。

l       data_came_in():

當連線上有資料可讀的時候,呼叫 httpconnection::data_came_in()。我們接下去看httpconnection::data_came_in()。

我們知道,bt client端與 tracker伺服器之間是通過tracke http 協議來進行通訊的。http協議分為請求(request)和響應(response),具體的協議請看相關的 rfc 文件。我這裡簡單講一下。

對 tracke 伺服器來說,它讀到的資料是 client 端的http 請求。

http請求以行為單位,行的結束符是「回車換行」,也就是 ascii 字元 「/r」和「/n」。

第一行是請求的 url,例如:

這行資料被空格分為三部分,

第一部分get表示命令,其它命令還有post、head等等,常用的就是get了。

第二部分是請求的url,這裡是 /announce?ip=aaaaa;port=bbbbbbb。如果是普通的上網瀏覽網頁,那麼url 就是我們要看的網頁在該web伺服器上的相對路徑。但是,這裡的url僅僅是互動資訊的一種方式,client 端把要報告給 tracker 的資訊,放在url中,例子裡面是 ip 和 port,更詳細的資訊請看「bt協議規範」中 tracker 協議部分。

第三部分是http協議的版本號,在程式中忽略。

接下來的每一行,都是http協議的訊息頭部分,例如:

host:www.sina.com.cn

accept-encoding:gzip

通過訊息頭,tracker伺服器可以知道 client端的一些資訊,這其中比較重要的就是 accept-encoding,如果是 gzip ,那麼說明 client 可以對 gzip 格式的資料進行解壓,那麼tracker伺服器就可以考慮用 gzip 把響應資料壓縮之後再傳回去,以減少網路流量。我們可以在**中看到相應的處理。

在訊息頭的最後,是乙個空行,表示訊息頭結束了。對get和head命令來說,訊息頭的結束,也就意味著整個client端的請求結束了。而對 post 命令來說,可能後面還跟著其它資料。由於我們的 tracker伺服器只接受 get 和 head 命令,所以在協議處理過程中,如果遇到空行,那麼就表示處理結束。

httpconnection::data_came_in() 用乙個迴圈來進行協議分析:

首先是尋找行結束符號:

i = self.buf.index('/n')

(我認為僅僅找 「/n」並不嚴謹,應該找 「/r/n」這個序列)。

如果沒有找到,那麼 index() 函式會丟擲乙個異常,而異常的處理是返回 true,表示資料不夠,需要繼續讀資料。

如果找到了,那麼 i 之前的字串就是完整的一行。於是呼叫協議處理函式,**是:

self.next_func = self.next_func(val)

在 httpconnection 的初始化的時候,有這麼一行**:

self.next_func = self.read_type

next_func 是用來儲存協議處理函式的,所以,第乙個被呼叫的協議處理函式就是 read_type()。它用來分析client端請求的第一行。在 read_type() 的最後,我們看到:

return self.read_header

這樣,在下一次呼叫 next_func 的時候,就是呼叫 read_header()了,也就是對 http 協議的訊息頭進行分析。

下面先看 read_type(),

它首先把 get 命令中的 url 部分儲存到 self.path中,因為這是 client端最關鍵的資訊,後面要用到。

然後檢查一下是否是get或者head命令,如果不是,那麼說明資料有錯誤。返回none,否則return self.read_header

接下來我們看read_header(),

這其中,最重要的就是對空行的處理,因為前面說了,空行表示協議分析結束。

在檢查完 client 端是否支援 gzip 編碼之後,呼叫:

r = self.handler.getfunc(self, self.path, self.headers)

在呼叫完 tracker::get() 之後,返回的是決定響應給 client 端的資料,

if r is not none:

self.answer(r)

最後,呼叫 answer() 來把這些資料傳送給 client 端。

l       connection_flushed():

tracker伺服器用的是非阻塞的網路 i/o ,所以不能保證在一次傳送資料的操作中,把要傳送的資料全部傳送出去。

這個函式,檢查在某個連線上需要傳送的資料,是否已經全部被傳送出去了,如果是的話,那麼關閉這個連線的傳送端。(為什麼僅僅關閉傳送端,而不是完全關閉這個連線了?疑惑)。 

BitTorrent 協議規範(翻譯)

元檔案和tracker的響應都採用的是一種簡單 有效 可擴充套件的格式,被稱為bencoding,它可以包含字串和整數。由於對不需要的字典關鍵字可以忽略,所以這種格式具有可擴充套件性,其它選項以後可以方便的加進來。bencoding格式如下 對於字串,首先是乙個字串的長度,然後是冒號,後面跟著實際的...

BitTorrent 協議規範(BT協議集合)七

bt種子檔案使用了一種叫bencoding的編碼方法來儲存資料。bencoding現有四種型別的資料 srings 字串 integers 整數 lists 列表 dictionaries 字典 編碼規則如下 strings 字串 編碼為 字串長度 字串 例如 4 test 表示為字串 test 4...

BitTorrent協議小結

1.bittorrent協議 2.bittorrent協議中的幾個概念 1 tracker伺服器 2 眾多客戶端 3 種子檔案 3.bittorrent協議在實際中運作的過程 1 要分享的資訊的某個bt客戶端,拿本機中的某個檔案或者目錄做種,生成種子檔案 torrent.然後,它會該告訴tracke...