代碼閱讀 - SocketServer.py

SocketServer.py<?XML:NAMESPACE PREFIX = O />

1.1  整體結構

在基類中調用並不實現的方法;類似於C++的純虛函數,強迫派生類實現。不一樣的是,如果派生類中不調用(派生類的用戶也不調用)該方法,那麼派生類就可以不實現這個方法。

對某些函數提供一個空的實現,相當於JAVAAdapter類,提供一個缺省實現。

RequestHandler的使用。並不是提供一個虛或者純虛函數來處理網絡請求,而是通過一個Handler類(或者函數,或者其它任何可以被調用的東西)來進行處理。

這就是傳說中的Strategy模式。

優點:處理網絡請求和監聽、接受網絡請求相分離;鬆散耦合;無論哪個模塊都更容易重用。

MixIn的結構更加優雅。

1.2  BaseServer結構

可以被調用,不能被覆蓋的函數:

Ø         __init__(server_address, RequestHandlerClass)
Base 中構造函數,保存 address handler class,不調用任何函數。
TCP中,構造 socket 對象,調用 server_bindserver_activate

Ø         serve_forever()
循環處理每一個請求,直到世界末日 while True: self.handle_request()
TCP中沒有覆蓋

UDP 中沒有覆蓋

Ø         handle_request()  # if you do not use serve_forever()
處理一個請求,在處理過程中,有可能產生阻塞。首先調用 get_request 獲得一個請求;然後調用verify_request對請求進行驗證;如果驗證成功,調用process_request對請求進行處理;如果處理過程中發生錯誤,調用handl_error處理錯誤,調用close_request釋放資源。
  try:

            request, client_address = self.get_request()

        except socket.error:

            return

        if self.verify_request(request, client_address):

            try:

                self.process_request(request, client_address)

            except:

                self.handle_error(request, client_address)

              self.close_request(request)

TCP 中沒有覆蓋
UDP 中沒有覆蓋

Ø         fileno() -> int   # for select()
BaseServer中沒有實現
TCP 中調用 socket.fileno
UDP 中沒有覆蓋

 

可以被覆蓋的函數

Ø         server_bind()
Base 中沒有實現
TCP 中調用 socket.bind
UDP 中沒有覆蓋

Ø         server_activate()
Base 中沒有實現
TCP 中調用 socket.listen
UDP 中實現爲空函數

Ø         get_request() -> request, client_address
BaseServer 中沒有實現
TCP 中調用 socket.accept
UDP 中調用 socket.recvfrom

Ø         verify_request(request, client_address)
Base 中實現爲空函數
TCP 中沒有覆蓋

Ø         server_close()
清理 server 所佔用的資源,可以被覆蓋。
Base 中實現爲空函數
TCP中調用 socket.close
UDP 中沒有覆蓋

Ø         process_request(request, client_address)
Base中調用 finish_request,然後 close_request
TCP 中沒有覆蓋
UDP 中沒有覆蓋

Ø         close_request(request)
清理 request 所佔用的資源,可以被覆蓋
Base 中實現爲空函數
TCP 中調用 socket.close
UDP 中實現爲空函數

Ø         handle_error()
Base 中打印錯誤信息。
TCP 中沒有覆蓋
UDP 中沒有覆蓋

向派生類提供的函數:

Ø         finish_request(request, client_address)
Base 中通過構造一個 RequestHandlerClass 實例來完成對request 的處理。
TCP 中沒有覆蓋
UDP 中沒有覆蓋

1.3  MixIn結構

Base Server 提供多線程和多進程支持。

1.3.1           ForkingMinxIn提供多進程支持

在列表active_children中保存最大數量爲max_children的進程。

process_request中調用collect_children,檢查進程數量是否達到限制。如果進程數量達到限制,需要等待一個進程退出後,纔會處理新請求。

在處理新的請求時,通過os.fork創建一個新進程:

1.        父進程
將子進程的oid加入active_children;調用close_request

2.        子進程
調用finish_request,如果發生錯誤,調用handle_error

1.3.2           ThreadingMixIn提供多線程支持

process_request中創建新線程,在新線程中調用finish_requestclose_request。支持daemon線程。

1.3.3           通過繼承使用

通過繼承某個MixInServer來達到目的。其中MixIn是第一基類,而Server是第二基類。MixIn中的process_request覆蓋Serverprocess_request

1.4  RequestHandler結構

BaseRequestHandler中有如下四個函數:

Ø         __init__,構造函數
保存request, client_address, server;依次調用 setup, handle, finish
這是一個Temeplate Method Pattern,派生類不能覆蓋。
如果派生類要提供自己的構造函數,就應該不使用BaseRequestHandler提供的處理模式。

Ø         setup,空函數

Ø         handle,空函數,處理請求

Ø         finish,空函數

在派生類StreamRequestHandler中:

Ø         覆蓋setup
根據request(對於TCP來說應該是socket對象)構造read file
write file
這樣派生類可以直接使用rfilewfile進行數據讀寫

Ø         覆蓋finish
對輸出文件調用flush;關閉兩個文件對象

在派生類DatagramRequestHandler中:

Ø         覆蓋setup
將輸入流通過StringIO方法封裝成read file;構造一個空的輸出流StringIO() write file

Ø         覆蓋finish
將輸出流中的數據發送到client_address

優點:無論是stream還是datagram方式,通過分別從這兩個類派生,都可以直接使用rfilewfile進行數據讀寫。

發佈了15 篇原創文章 · 獲贊 0 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章