<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 56,  comments - 12,  trackbacks - 0

    本篇文章分析 HTTPHandler 類,它在 HTTPHandler.py 文件中。

    上一篇我們講到, RawServer 只負(fù)責(zé)網(wǎng)絡(luò) I/O ,也就是從網(wǎng)絡(luò)上讀取和發(fā)送數(shù)據(jù),至于讀到的數(shù)據(jù)如何分析,以及應(yīng)該發(fā)送什么樣的數(shù)據(jù),則交給 Handler 類來處理。如果是用 c++ 來實(shí)現(xiàn)的話,那么 Handler 應(yīng)該是一個接口類(提供幾個虛函數(shù)作為接口),但是 python 動態(tài)語言的特性,并不需要專門定義這么一個接口類,所以實(shí)際上并沒有 Handler 這么一個類。任何一個提供了以下成員函數(shù)的類,都可以作為一個 Handler 類來與 RawServer 配合,它們是:

     

    external_connection_made() :在建立新的連接的時(shí)候被調(diào)用

    data_came_in() :連接上有數(shù)據(jù)可讀的時(shí)候被調(diào)用

    connection_flushed() :當(dāng)在某個連接上發(fā)送完數(shù)據(jù)之后被調(diào)用

     

           HTTPHandler 就是這樣一個 Handler 類,它具備以上接口。

           HTTPHandler 代碼很少,因?yàn)樗阎饕ぷ饔纸唤o HTTPConnection 了。

           我們看 HTTPHandler 類的這幾個函數(shù):

     

    l         external_connection_made()

    每當(dāng)新來一個連接的時(shí)候,就創(chuàng)建一個 HTTPConnection 類。

     

    l         data_came_in()

    當(dāng)連接上有數(shù)據(jù)可讀的時(shí)候,調(diào)用 HTTPConnection::data_came_in() 。我們接下去看 HTTPConnection::data_came_in()

     

    我們知道, BT client 端與 tracker 服務(wù)器之間是通過 tracke HTTP 協(xié)議來進(jìn)行通信的。 HTTP 協(xié)議分為請求( request )和響應(yīng)( response ),具體的協(xié)議請看相關(guān)的 RFC 文檔。我這里簡單講一下。

    tracke 服務(wù)器來說,它讀到的數(shù)據(jù)是 client 端的 HTTP 請求。

     

    HTTP 請求以行為單位,行的結(jié)束符是“回車換行”,也就是 ascii 字符 \r ”和“ \n ”。

     

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

    GET              /announce?ip=aaaaa;port=bbbbbbb       HTTP/1.0

     

    這行數(shù)據(jù)被空格分為三部分,

    第一部分 GET 表示命令,其它命令還有 POST HEAD 等等,常用的就是 GET 了。

    第二部分是請求的 URL ,這里是 /announce?ip=aaaaa;port=bbbbbbb 。如果是普通的上網(wǎng)瀏覽網(wǎng)頁,那么 URL 就是我們要看的網(wǎng)頁在該 web 服務(wù)器上的相對路徑。但是,這里的 URL 僅僅是交互信息的一種方式, client 端把要報(bào)告給 tracker 的信息,放在 URL 中,例子里面是 ip port ,更詳細(xì)的信息請看“ BT 協(xié)議規(guī)范”中 tracker 協(xié)議部分。

    第三部分是 HTTP 協(xié)議的版本號,在程序中忽略。

     

    接下來的每一行,都是 HTTP 協(xié)議的消息頭部分,例如:

    Host:www.sina.com.cn

    Accept-encoding:gzip

     

    通過消息頭, tracker 服務(wù)器可以知道 client 端的一些信息,這其中比較重要的就是 Accept-encoding ,如果是 gzip ,那么說明 client 可以對 gzip 格式的數(shù)據(jù)進(jìn)行解壓,那么 tracker 服務(wù)器就可以考慮用 gzip 把響應(yīng)數(shù)據(jù)壓縮之后再傳回去,以減少網(wǎng)絡(luò)流量。我們可以在代碼中看到相應(yīng)的處理。

    在消息頭的最后,是一個空行,表示消息頭結(jié)束了。對 GET HEAD 命令來說,消息頭的結(jié)束,也就意味著整個 client 端的請求結(jié)束了。而對 POST 命令來說,可能后面還跟著其它數(shù)據(jù)。由于我們的 tracker 服務(wù)器只接受 GET HEAD 命令,所以在協(xié)議處理過程中,如果遇到空行,那么就表示處理結(jié)束。

     

     

    HTTPConnection::data_came_in() 用一個循環(huán)來進(jìn)行協(xié)議分析:

    首先是尋找行結(jié)束符號:

     

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

     

    (我認(rèn)為僅僅找 \n ”并不嚴(yán)謹(jǐn),應(yīng)該找 \r\n ”這個序列)。

    如果沒有找到,那么 index() 函數(shù)會拋出一個異常,而異常的處理是返回 True ,表示數(shù)據(jù)不夠,需要繼續(xù)讀數(shù)據(jù)。

    如果找到了,那么 i   之前的字符串就是完整的一行。于是調(diào)用協(xié)議處理函數(shù),代碼是:

     

    self.next_func = self.next_func(val)

     

    HTTPConnection 的初始化的時(shí)候,有這么一行代碼:

     

    self.next_func = self.read_type

     

    next_func 是用來保存協(xié)議處理函數(shù)的,所以,第一個被調(diào)用的協(xié)議處理函數(shù)就是 read_type() 。它用來分析 client 端請求的第一行。在 read_type() 的最后,我們看到:

    return self.read_header

     

    這樣,在下一次調(diào)用 next_func 的時(shí)候,就是調(diào)用 read_header() 了,也就是對 HTTP 協(xié)議的消息頭進(jìn)行分析。

     

    下面先看 read_type()

    它首先把 GET 命令中的 URL 部分保存到 self.path 中,因?yàn)檫@是 client 端最關(guān)鍵的信息,后面要用到。

    然后檢查一下是否是 GET 或者 HEAD 命令,如果不是,那么說明數(shù)據(jù)有錯誤。返回 None ,否則 return self.read_header

     

    接下來我們看 read_header()

    這其中,最重要的就是對空行的處理,因?yàn)榍懊嬲f了,空行表示協(xié)議分析結(jié)束。

    在檢查完 client 端是否支持 gzip 編碼之后,調(diào)用:

     

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

     

    通過一層層往后追查,發(fā)現(xiàn) getfunc() 實(shí)際是 Tracker::get() ,也就是說,真正對 client 端發(fā)來的請求進(jìn)行分析,以及決定如何響應(yīng),是由 Tracker 來決定的。是的,這個 Tracker 在我們 tracker 服務(wù)器源碼分析系列的第一篇文章中就已經(jīng)看到了。在創(chuàng)建 RawServer 之后,馬上就創(chuàng)建了一個 Tracker 對象。所以,要了解 tracker 服務(wù)器到底是如何工作的,需要我們深入進(jìn)去分析 Tracker 類,那就是我們下一篇文章的工作了。

     

    在調(diào)用完 Tracker::get() 之后,返回的是決定響應(yīng)給 client 端的數(shù)據(jù),

    if r is not None:

    self.answer(r)

    最后,調(diào)用 answer() 來把這些數(shù)據(jù)發(fā)送給 client 端。

     

    answer() 的分析,我們在下一篇分析 Tracker 類的文章中一并講解。

     

    l         connection_flushed()

    tracker 服務(wù)器用的是非阻塞的網(wǎng)絡(luò) I/O ,所以不能保證在一次發(fā)送數(shù)據(jù)的操作中,把要發(fā)送的數(shù)據(jù)全部發(fā)送出去。

    這個函數(shù),檢查在某個連接上需要發(fā)送的數(shù)據(jù),是否已經(jīng)全部被發(fā)送出去了,如果是的話,那么關(guān)閉這個連接的發(fā)送端。(為什么僅僅關(guān)閉發(fā)送端,而不是完全關(guān)閉這個連接了?疑惑)。

    posted on 2007-01-19 00:18 苦笑枯 閱讀(386) 評論(0)  編輯  收藏 所屬分類: P2P
    收藏來自互聯(lián)網(wǎng),僅供學(xué)習(xí)。若有侵權(quán),請與我聯(lián)系!

    <2007年1月>
    31123456
    78910111213
    14151617181920
    21222324252627
    28293031123
    45678910

    常用鏈接

    留言簿(2)

    隨筆分類(56)

    隨筆檔案(56)

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 免费无码一区二区三区蜜桃 | 一边摸一边爽一边叫床免费视频| 亚洲熟妇无码AV不卡在线播放 | 国产公开免费人成视频| 国内大片在线免费看| 日韩精品免费电影| 国产成人一区二区三区免费视频| 精品国产精品久久一区免费式| 精品免费国产一区二区三区| 国产免费观看青青草原网站| 伊在人亚洲香蕉精品区麻豆| 精品亚洲一区二区三区在线播放| 伊伊人成亚洲综合人网7777| 亚洲国产精品va在线播放| 亚洲国产国产综合一区首页| 色拍自拍亚洲综合图区| 亚洲一卡2卡4卡5卡6卡在线99 | 国产专区一va亚洲v天堂| 久久精品国产亚洲麻豆| 久久久亚洲欧洲日产国码aⅴ | 亚洲国产一区二区a毛片| 亚洲欧洲日产国码二区首页 | 丁香五月亚洲综合深深爱| 亚洲Av综合色区无码专区桃色| 久久久久亚洲AV无码观看| 亚洲kkk4444在线观看| 337P日本欧洲亚洲大胆精品| 国产精品无码免费专区午夜| 久久大香伊焦在人线免费| 久久久久久国产精品免费无码| 最新欧洲大片免费在线| 全部免费毛片在线| 国产V亚洲V天堂A无码| 精品亚洲成A人无码成A在线观看| 国产精品亚洲а∨无码播放麻豆| 精选影视免费在线 | 57pao国产成视频免费播放| 日韩免费a级在线观看| 亚洲国产精品无码中文字| 亚洲制服丝袜第一页| 欧亚一级毛片免费看|