天天看點

SocketServer源碼學習(一)

SocketServer其實是對socket更進階的封裝正如官網上說的:

The socketserver module simplifies the task of writing network servers.

我們可以先打開以下SocketServer的源碼,看一下源碼中整體的架構

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      

先看一下源碼内容如下:

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源碼

源碼内容如下:

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

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

def finish_request(self, request, client_address):
    """Finish one request by instantiating RequestHandlerClass."""
    self.RequestHandlerClass(request, client_address, self)      

關于請求的部分到這裡就已經處理完畢,接下來是要對資料的處理,finish_request方法将會處理完畢請求。建立requestHandler對象,并通過requestHandler做具體的處理。

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方法

所有的努力都值得期許,每一份夢想都應該灌溉!

繼續閱讀