<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)該是一個(gè)接口類(提供幾個(gè)虛函數(shù)作為接口),但是 python 動(dòng)態(tài)語言的特性,并不需要專門定義這么一個(gè)接口類,所以實(shí)際上并沒有 Handler 這么一個(gè)類。任何一個(gè)提供了以下成員函數(shù)的類,都可以作為一個(gè) Handler 類來與 RawServer 配合,它們是:

     

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

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

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

     

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

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

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

     

    l         external_connection_made()

    每當(dāng)新來一個(gè)連接的時(shí)候,就創(chuàng)建一個(gè) 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é)議的版本號(hào),在程序中忽略。

     

    接下來的每一行,都是 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)的處理。

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

     

     

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

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

     

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

     

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

    如果沒有找到,那么 index() 函數(shù)會(huì)拋出一個(gè)異常,而異常的處理是返回 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ù)的,所以,第一個(gè)被調(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ù)有錯(cuò)誤。返回 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 來決定的。是的,這個(gè) Tracker 在我們 tracker 服務(wù)器源碼分析系列的第一篇文章中就已經(jīng)看到了。在創(chuàng)建 RawServer 之后,馬上就創(chuàng)建了一個(gè) 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ā)送出去。

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

    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)

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 成人毛片免费在线观看| 国产日产成人免费视频在线观看| 亚洲视频在线不卡| 欧洲精品成人免费视频在线观看 | 亚洲精品无码专区在线| 免费一级特黄特色大片在线| 中文字幕免费在线看线人动作大片| 亚洲狠狠综合久久| 好爽好紧好大的免费视频国产| 中文字幕久无码免费久久| 亚洲日本久久一区二区va| mm1313亚洲国产精品美女| 国产免费丝袜调教视频| 一级毛片免费视频网站| 亚洲国产视频一区| 国产精品亚洲产品一区二区三区 | 亚洲AV色香蕉一区二区| 永久免费看bbb| 三年片在线观看免费大全电影 | 亚洲熟妇少妇任你躁在线观看| 久久久久久久亚洲精品| 性生交片免费无码看人| 西西人体免费视频| 久久精品国产亚洲AV| 亚洲国产成人无码av在线播放| 中文字幕日韩亚洲| 在线观看免费大黄网站| 免费A级毛片av无码| 黄色网址免费在线观看| 亚洲av无码av在线播放| 亚洲狠狠ady亚洲精品大秀| 亚洲人妻av伦理| 免费的一级片网站| 国产1000部成人免费视频| 久久国产精品免费一区二区三区| 亚洲精品V天堂中文字幕| 亚洲蜜芽在线精品一区| 亚洲精品成人片在线播放| www.亚洲色图.com| 国产午夜免费福利红片| 欧美男同gv免费网站观看|