SocketServer其實是對socket更高級的封裝正如官網上說的:The socketserver module simplifies the task of writing network servers. 我們可以先打開以下SocketServer的源碼,看一下源碼中整體的框架 從上圖我們 ...
SocketServer其實是對socket更高級的封裝正如官網上說的:
The socketserver module simplifies the task of writing network servers.
我們可以先打開以下SocketServer的源碼,看一下源碼中整體的框架
從上圖我們可以看出SocketServer主要被抽象為兩個主要的類:
BaseServer類,用於處理連接相關的網路操作
BaseRequestHandler類,用於實際處理數據相關的操作
SocketServer還提供了兩個MixIn類:ThreadingMinxIn和ForkingMixinl
用於擴展server,實現多進程和多線程
下麵從會從這幾個主要的類開始做一個整體的分析,瞭解SocketServer的處理流程
BaseServer
先列一下這裡所包含的方法:
server_activate
serve_forever
shutdown
service_actions
handle_request
handlerequest_noblock
handle_timeout
verify_request
process_request
server_close
finish_request
shutdown_request
close_request
handle_error
先看一下BaseServer的初始化函數,其實並沒有過多的參數,主要就是實現了創建server對象,並初始化server地址和處理請求的類:RequestHandlerClass
def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass self.__is_shut_down = threading.Event() self.__shutdown_request = False
serve_forever
先看一下源碼內容如下:
def serve_forever(self, poll_interval=0.5): """Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. """ self.__is_shut_down.clear() try: # XXX: Consider using another file descriptor or connecting to the # socket to wake this up instead of polling. Polling reduces our # responsiveness to a shutdown request and wastes cpu at all other # times. with _ServerSelector() as selector: selector.register(self, selectors.EVENT_READ) while not self.__shutdown_request: ready = selector.select(poll_interval) if ready: self._handle_request_noblock() self.service_actions() finally: self.__shutdown_request = False self.__is_shut_down.set()
當創建server對象之後,我們會使用server對象開啟一個無限迴圈,即調用serve_forever,
下麵是它的源碼,接受一個參數poll_interval,用於表示select輪詢的時間,然後進入一個死迴圈,用select方法進行網路IO的監聽,這裡通過調用selector.register(self, selectors.EVENT_READ)進行了註冊,當ready有返回是,表示有IO連接或者數據,這個時候會調用_handle_request_noblock
接著看一下_handle_request_noblock源碼
handlerequest_noblock
源碼內容如下:
def _handle_request_noblock(self): """Handle one request, without blocking. I assume that selector.select() has returned that the socket is readable before this function was called, so there should be no risk of blocking in get_request(). """ try: request, client_address = self.get_request() except OSError: return if self.verify_request(request, client_address): try: self.process_request(request, client_address) except: self.handle_error(request, client_address) self.shutdown_request(request) else: self.shutdown_request(request)
handlerequest_noblock方法即開始處理一個請求,並且是非阻塞。該方法通過get_request方法獲取連接,具體的實現在其子類。一旦得到了連接,調用verify_request方法驗證請求。驗證通過,即調用process_request處理請求。如果中途出現錯誤,則調用handle_error處理錯誤,以及shutdown_request結束連接。
而verify_request中預設直接返回True,所以當驗證通過後講調用process_request
process_request
源碼內容如下:
def process_request(self, request, client_address): """Call finish_request. Overridden by ForkingMixIn and ThreadingMixIn. """ self.finish_request(request, client_address) self.shutdown_request(request)
就像源碼中描述的那樣:Overridden by ForkingMixIn and ThreadingMixIn.
process_request方法是mixin的入口,MixIn子類通過重寫該方法,進行多線程或多進程的配置。調用finish_request完成請求的處理,同時調用shutdown_request結束請求。繼續查看finish_request
finish_request
源碼內容如下:
def finish_request(self, request, client_address): """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self)
關於請求的部分到這裡就已經處理完畢,接下來是要對數據的處理,finish_request方法將會處理完畢請求。創建requestHandler對象,並通過requestHandler做具體的處理。
BaseRequestHandler
就像我們前面說的:
BaseServer類,用於處理連接相關的網路操作
BaseRequestHandler類,用於實際處理數據相關的操作
還是從初始化函數里看源碼:
def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish()
該類會處理每一個請求。初始化對象的時候,設置請求request對象。然後調用setup方法,子類會重寫該方法,用於處理socket連接。接下來的將是handler和finish方法。所有對請求的處理,都可以重寫handler方法。
SocketServer的一個服務端的簡單例子
直接上代碼了:
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address)) print(self.data) self.request.sendall(self.data.upper()) except ConnectionResetError as e: print(e) break if __name__ == '__main__': host,port = "127.0.0.1",9999 server = socketserver.TCPServer((host,port),MyTCPHandler) server.serve_forever()
通過對源碼的分析我們已經知道了對數據的處理部分都是在BaseRequestHandler這個類中,而我們的主要處理邏輯也就是在這部分,所以我繼承了這個類,重寫了handle方法