<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

    這篇文章,我們來分析 RawServer 以及一些相關的類。 RawServer 類的實現代碼,在 BitTorrent 子目錄的 RawServer.py

     

    RawServer 這個類的作用是實現一個網絡服務器。關于網絡編程的知識,《 unix 網絡編程:卷 1 》是最經典的書籍,你如果對這塊不了解,建議抽時間看看這本書。 RawServer 實現的是一種事件多路復用、非阻塞的網絡模型。它使用的是 poll() (而不是我們常見的 select() ,關于 poll select 的比較,也在《 unix 網絡編程:卷 1 》中有介紹)函數,處理過程大致是這樣的:

    首先創建一個監聽 socket ,然后將這個 socket 加入 poll 的事件源;

    隨后進入服務處理循環,即:

     

    調用 poll() 函數,這個函數會阻塞,直到網絡上有某些事件發生或者超時才返回給調用者;

    poll() 返回之后,先檢查一下是否有沒有處理的任務,如果有,那么先完成這些任務。然后根據事件類型進行處理。

    如果是連接請求(監聽 socket 上的 POLLIN 事件)到來,它 accept 這個請求,如果 accept 成功,那么就和一個 client 建立了連接,于是將 accept() 新創建的 socket 加入 poll 的事件源;

    如果在已經建立的連接上(連接 socket 上的 POLLIN 事件),有數據可讀,那么將數據從 client 端讀過來,做進一步處理;

    如果已經建立的連接已經準備好(連接 socket 上的 POLLOUT 事件),可以發送數據,則檢查是否有數據需要發送,如果有,那么發送數據給 client 端。

     

    (所以, tracker 是一個單進程的服務器,并沒有用到線程。)

     

    Bram Cohen 認為軟件的可維護性非常重要,使代碼易于維護的重要一條就是設計可重用的類, RawServer 在設計的時候,充分考慮到了可重用性,集中表現在兩個地方:

    1、  將網絡 I/O 和數據分析處理分離。

    網絡服務器的事件多路復用、網絡 I/O 部分通常是固定不變的,而數據在讀取之后,進行分析處理的過程則是可變的。 RawServer 將可變的數據處理工作,交給另外一個抽象的類 Handler (實際上并沒有這么一個類)來處理。比如,在 tracker 服務器的實現中,具體使用的就是 HTTPHandler 類,而在 以后將要分析的 BT client 實現代碼中,用到的具體的 Handler Encoder 類。

     

    2、  采用任務隊列來抽象出任務處理的過程。

    RawServer 維護了一個任務隊列 unscheduled_tasks (實際是一個二元組的 list ,二元組的第一項是一個函數,第二項是超時時間)。在初始化的時候,首先向這個隊列中加入一個任務: scan_for_timeouts() ,這樣,每隔一段時間,服務器就會去檢查一下是否有連接超時。如果有其它

     

    RawServer 的成員函數中,對外暴露的有:

     

    u       __init__ :(初始化函數)

     

    u       add_task()

           在任務列表中增加一項任務(一個任務是一個函數以及一個指定的超時時間的組合)

     

    u       bind()

           首先創建一個 socket ,然后設置 socket 的屬性: SO_REUSEADDR IP_TOS, ,這兩個屬性的具體含義請參考《 unix 網絡編程:卷 1 》,另外還將 socket 設置為非阻塞的。相對于阻塞的 socket 來說,非阻塞的 socket 在網絡 I/O 性能上要提高許多,但是與此同時,編程的復雜度也要提高一些。象 tracker 這種可能同時要處理成千上萬個并發連接的服務器,只能采用非阻塞的 socket

           然后將該 socket 和指定 ip 已經端口綁定;

           最后把這個 socket 加入 poll 的事件源。

     

    u       start_connection()

           對外主動建立一個連接,這個函數在處理 NAT 穿越的時候用到了,我們后面分析到 NAT 穿越的時候,再具體講解。

     

    u       listen_forever()

           這個函數的功能就是實現了我在前面描述的網絡服務器的處理過程。我們看到,它唯一的參數是 handler handler 的作用就是封裝了對數據的具體處理。

    listen_forever() 把對網絡事件的處理過程,交給了 handle_events()

     

    其它函數,包括 handle_events() ,都是內部函數(也就是外部不會直接來調用這些函數)。 Python 沒有 c++ 那樣 public protected private 這樣的保護機制, python 類的內部函數命名的慣例是以下劃線開始,例如 RawServer 中的 _close_dead() 等。

     

    u       handle_events()

    事件處理過程,主要是根據三種不同的網絡事件分別處理,一是連接事件,二是讀事件、三是寫事件。

     

    if sock == self.server.fileno()

     

    這段代碼判斷發生事件的 socket 是否是監聽 socket ,如果是,那么說明是連接事件。

    連接事件的處理:

    通過 accept 來接受連接,并將新建立的 socket 設置為非阻塞。

    判斷當前連接數是否已經達到了最大值(為了限制并發連接的數目,在初始化 RawServer 的時候,需要指定最大連接數目),如果已經達到最大值,那么關閉這個新建的連接。

    否則,根據新的 socket 創建一個 SingleSocket 對象,( SingleSocket 封裝了對 socket 的操作。)將這個對象加入內部的列表 single_sockets 中,以備后用。

    將這個新 socket 加入 poll 的事件源

    最后,調用 Handler external_connection_made() 函數,關于這個函數,在后面分析 HTTPHandler 時再討論。

     

    if (event & POLLIN) != 0:

    這段代碼判斷是否是讀事件

    讀事件的處理:

    首先刷新一下連接的最后更新時間 last_hit )。

    然后讀取數據;

    如果什么也沒讀到,那么說明連接被關閉了(在網絡編程中,如果一個連接正常的被關閉,那么,也會觸發讀事件,只不過什么也讀不到)

    否則,調用 Handler data_came_in() 函數來處理讀到的數據。

     

    if (event & POLLOUT) != 0 and s.socket is not None and not s.is_flushed():

    這段代碼判斷是否是寫事件,而且確實有數據需要發送。在一個連接可以寫的時候,就會發生寫事件。

    寫事件的處理:

    實際代碼是在 SingleSocket try_write() 函數中。

    在一個非阻塞的連接上發送指定大小的數據,很可能在一次發送過程中,數據沒有被完全發送出去(只發送了一部分)就返回了,所以,每次 write 之后,必須判斷是否完全發送了數據。如果沒有發送完,那么下次有讀事件的時候,還得回來繼續發送未完得數據。這也是這個函數叫做 try_write 的原因吧。

    try_write() 在最后,要重新設置 poll 的事件源。如果數據全部發送完畢了,那么只需要監聽讀事件( POLLIN )否則,既要監聽讀事件,也要監聽寫事件( POLLOUT ),這樣,一旦連接變的可寫,可以繼續將剩下的數據發送出去。

     

    u       scan_for_timeouts()

    任務處理函數,它首先把自身加入未處理任務隊列中,這樣,經過一段時間,可以保證這個函數再次被調用,從而達到周期性調用的效果。

    它檢查每個連接是否超過指定時間沒有被刷新,如果是,則該連接可能已經僵死,那么它關閉這個連接。

     

    u       pop_unscheduled()

    從任務列表中彈出一個未處理的任務。

     

     

    RawServer 配合使用的是 SingleSocket 類,這是一個輔助類,主要目的是封裝對 socket 的處理吧。包括數據的發送,都交給它來處理了。這個類比較簡單,大家可以自己去看,我就不羅嗦了。

     

     

    以上是對 RasServer 的具體實現的一個分析,可能讀者看的還是暈暈糊糊,沒辦法,還是必須自己去看源代碼,然后在遇到問題的時候,回頭再來看這篇文章,才會有幫助。如果不親自看源碼,終究是紙上談兵。

     

    我們再來小結一下。

    RawServer 封裝了網絡服務器的實現細節,它實現了一種事件多路處理、非阻塞的網絡模型。它主要負責建立新的連接,從網絡讀取和發送數據,而對讀到的數據的具體處理工作,交給 Handler 類來處理,從而把網絡 I/O 和數據處理分離開來,使得 RawServer 可以重用。 Handler 類是在調用 listen_forever() 的時候,由調用者傳遞進來的,具體到 tracker 服務器,就是 HTTPHandler 。有了 RawServer tracker 就可以作為一個網絡服務器運行了。

    下一節,我們開始分析具體實現 tracker HTTP 協議處理的 HTTPHandler 類和 Tracker 類。

    posted on 2007-01-19 00:18 苦笑枯 閱讀(373) 評論(0)  編輯  收藏 所屬分類: P2P
    收藏來自互聯網,僅供學習。若有侵權,請與我聯系!

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

    常用鏈接

    留言簿(2)

    隨筆分類(56)

    隨筆檔案(56)

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 黄色网址大全免费| a视频免费在线观看| 亚洲午夜激情视频| 无码成A毛片免费| 亚洲精品无码久久久久牙蜜区| 国产免费AV片无码永久免费| 中文字幕成人免费高清在线| 亚洲午夜国产精品| 亚洲成a人片在线观看久| 久久免费看少妇高潮V片特黄| 日本免费一区二区三区| 亚洲一区精彩视频| 亚洲真人无码永久在线| 美女被免费喷白浆视频| caoporn成人免费公开| 亚洲jjzzjjzz在线播放| 免费国产黄网站在线观看可以下载| 久久亚洲国产成人影院| 国产精品亚洲αv天堂无码| 国产成人福利免费视频| 国产va免费精品| 亚洲日本在线电影| 亚洲视频在线播放| 久久久久久A亚洲欧洲AV冫| 扒开双腿猛进入爽爽免费视频| a级片免费在线播放| 亚洲av乱码中文一区二区三区| 亚洲电影一区二区| jlzzjlzz亚洲乱熟在线播放| 免费做爰猛烈吃奶摸视频在线观看| 拍拍拍无挡免费视频网站| 国产精品亚洲专区在线播放| 亚洲精品韩国美女在线| 国产亚洲色婷婷久久99精品| 四虎影视永久免费视频观看| 91嫩草国产在线观看免费| 久久久久久成人毛片免费看 | 色偷偷噜噜噜亚洲男人| 亚洲网址在线观看| 亚洲国产精品国自产拍AV| 亚洲国产天堂久久综合|