<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无码无卡免费| 成人电影在线免费观看| 五月婷婷综合免费| 麻豆亚洲av熟女国产一区二| 免费无码av片在线观看| 久久精品国产亚洲精品| 丰满人妻一区二区三区免费视频| 亚洲第一区精品观看| 又黄又大的激情视频在线观看免费视频社区在线 | 少妇人妻偷人精品免费视频| 亚洲中文字幕无码日韩| 三年片在线观看免费| 亚洲AV无码久久精品成人| 国产免费网站看v片在线| 亚洲成AV人片在线播放无码| a级毛片毛片免费观看永久| 亚洲成AV人在线播放无码 | 一级毛片大全免费播放下载| 久久亚洲国产成人精品无码区| www免费黄色网| 国产亚洲免费的视频看| 日本免费一区二区三区| 亚洲图片校园春色| 女性自慰aⅴ片高清免费| 色噜噜的亚洲男人的天堂| 大胆亚洲人体视频| a级毛片高清免费视频| 亚洲女人18毛片水真多| 日韩成全视频观看免费观看高清| 日韩精品无码永久免费网站| 亚洲第一AAAAA片| 国产在线国偷精品产拍免费| 国产亚洲综合久久| 亚洲av中文无码乱人伦在线咪咕| 人与禽交免费网站视频| 亚洲AV成人无码网天堂| 国产亚洲综合成人91精品| 久久久久久免费视频| 日本高清免费中文在线看| 无套内谢孕妇毛片免费看看| 久久精品国产亚洲一区二区三区|