国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python的socket模塊源碼中的一些實現要點分析

2019-11-25 16:45:19
字體:
來源:轉載
供稿:網友

BaseServer 和 BaseRequestHandler
Python為網絡編程提高了更高級的封裝。SocketServer.py 提供了不少網絡服務的類。它們的設計很優雅。Python把網絡服務抽象成兩個主要的類,一個是Server類,用于處理連接相關的網絡操作,另外一個則是RequestHandler類,用于處理數據相關的操作。并且提供兩個MixIn 類,用于擴展 Server,實現多進程或多線程。在構建網絡服務的時候,Server 和 RequestHandler 并不是分開的,RequestHandler的實例對象在Server 內配合 Server工作。

改模塊的主要幾個Server關系如下:

    +------------+    | BaseServer |    +------------+       |       v    +-----------+    +------------------+    | TCPServer |------->| UnixStreamServer |    +-----------+    +------------------+       |       v    +-----------+    +--------------------+    | UDPServer |------->| UnixDatagramServer |    +-----------+    +--------------------+

BaseServer 分析
BaseServer 通過__init__初始化,對外提供serve_forever和 handler_request方法。

init 初始化:

  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

__init__源碼很簡單。主要作用是創建server對象,并初始化server地址和處理請求的class。熟悉socket編程應該很清楚,server_address是一個包含主機和端口的元組。

serve_forever
創建了server對象之后,就需要使用server對象開啟一個無限循環,下面來分析serve_forever的源碼。

  def serve_forever(self, poll_interval=0.5):    self.__is_shut_down.clear()    try:      while not self.__shutdown_request:        r, w, e = _eintr_retry(select.select, [self], [], [],                    poll_interval)        if self in r:          self._handle_request_noblock()    finally:      self.__shutdown_request = False      self.__is_shut_down.set()

serve_forever接受一個參數poll_interval,用于表示select輪詢的時間。然后進入一個無限循環,調用select方式進行網絡IO的監聽。

如果select函數返回,表示有IO連接或數據,那么將會調用_handle_request_noblock方法。

_handle_request_noblock  def _handle_request_noblock(self):    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.shutdown_request(request)

_handle_request_noblock方法即開始處理一個請求,并且是非阻塞。該方法通過get_request方法獲取連接,具體的實現在其子類。一旦得到了連接,調用verify_request方法驗證請求。驗證通過,即調用process_request處理請求。如果中途出現錯誤,則調用handle_error處理錯誤,以及shutdown_request結束連接。

verify_request  def verify_request(self, request, client_address):    return True

該方法對request進行驗證,通常會被子類重寫。簡單的返回True即可,然后進入process_request方法處理請求。

process_request  def process_request(self, request, client_address):    self.finish_request(request, client_address)    self.shutdown_request(request)

process_request方法是mixin的入口,MixIn子類通過重寫該方法,進行多線程或多進程的配置。調用finish_request完成請求的處理,同時調用shutdown_request結束請求。

finish_request  def finish_request(self, request, client_address):    self.RequestHandlerClass(request, client_address, self)

finish_request方法將會處理完畢請求。創建requestHandler對象,并通過requestHandler做具體的處理。

BaseRequestHandler 分析
所有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方法。

至此,整個Python提供的Server方式即介紹完畢??偨Y一下,構建一個網絡服務,需要一個BaseServer用于處理網絡IO,同時在內部創建requestHandler對象,對所有具體的請求做處理。

BaseServer - BaseRequestHandler

__init__(server_address, RequestHandlerClass):   BaseServer.server_address  BaseServer.RequestHandlerClassserve_forever():   select()   BaseServer._handle_request_noblock()    BaseServer.get_request() -> request, client_addres    BaseServer.verify_request()      BaseServer.process_request()        BaseServer.process_request()          BaseServer.finish_request()            BaseServer.RequestHandlerClass()              BaseRequestHandler.__init__(request)                BaseRequestHandler.request                BaseRequestHandler.client_address = client_address                BaseRequestHandler.setup()                BaseRequestHandler.handle()          BaseServer.shutdown_request()            BaseServer.close_request()      BaseServer.shutdown_request()        BaseServer.close_request()

BaseServer 和 BaseRequestHandler是網絡處理的兩個基類。實際應用中,網絡操作更多是使用 TCP 或 HTTP 協議。SocketServer.py 也提供了更高級的TCP、UDP封裝。下面就來看下關于TCP方面的網絡模塊(UDP和TCP的在代碼組織上差別不是特別大,暫且忽略)。

TCPServer
TCPServer 繼承了BaseServer,初始化的時候,進行了socket套接字的創建。

def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):  BaseServer.__init__(self, server_address, RequestHandlerClass)  self.socket = socket.socket(self.address_family,                self.socket_type)  if bind_and_activate:    self.server_bind()    self.server_activate()

__init__ 方法通過 socket模塊創建了socket對象,然后進行調用server_bind和server_activate。

server_binddef server_bind(self):  if self.allow_reuse_address:    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  self.socket.bind(self.server_address)  self.server_address = self.socket.getsockname()

server_bind 方法進行socket對象的bind操作,以及設置socket相關屬性,如網絡地址的復用。

server_activatedef server_activate(self):  self.socket.listen(self.request_queue_size)

server_activate 方法也比較簡單,添加socket對象的listen。

get_request
該類最重要的方法就是 get_request。該方法進行返回socket對象的請求連接。

  def get_request(self):  """Get the request and client address from the socket.  """  return self.socket.accept()

get_request方法是在BaseServer基類中的_handle_request_noblock中調用,從那里里傳入套接字對象獲取的連接信息。如果是UDPServer,這里獲取的就是UDP連接。

此外,TCPServer還提供了一個 fileno 方法,提供給基類的select調用返回文件描述符。

StreamRequestHandler
TCPServer實現了使用tcp套接字的網絡服務,Handler方面則是對應的StreamRequestHandler。它繼承了BaseRequestHandler。基類的setup方法和finish方法被它重寫,用于通過連接實現緩存文件的讀寫操作。

setup方法:

def setup(self):  self.connection = self.request  if self.timeout is not None:    self.connection.settimeout(self.timeout)  if self.disable_nagle_algorithm:    self.connection.setsockopt(socket.IPPROTO_TCP,                  socket.TCP_NODELAY, True)  self.rfile = self.connection.makefile('rb', self.rbufsize)  self.wfile = self.connection.makefile('wb', self.wbufsize)

setup判斷了是否使用nagle算法。然后設置對應的連接屬性。最重要的就是創建了一個可讀(rfile)和一個可寫(wfile)的“文件”對象,他們實際上并不是創建了文件,而是封裝了讀取數據和發送數據的操作,抽象成為對文件的操作。可以理解為 self.rfile 就是讀取客戶端數據的對象,它有一些方法可以讀取數據。self.wfile則是用來發送數據給客戶端的對象。后面的操作,客戶端數據到來會被寫入緩沖區可讀,需要向客戶端發送數據的時候,只需要向可寫的文件中write數據即可。

實現TCP服務需要使用TCPServer和StreamRequestHandler共同協作。大致函數調用流程如下,函數調用用括號表示,賦值不帶括號,沒有類前綴的表示系統調用:

TCPServer - StreamRequestHandler

__init__(server_address, RequestHandlerClass):   BaseServer.server_address  BaseServer.RequestHandlerClass  TCPServer.socket = socket.socket(self.address_family, self.socket_type)  TCPServer.server_bind()  TCPServer.server_activate()serve_forever():   select()   BaseServer._handle_request_noblock()    TCPServer.get_request() -> request, client_addres      socket.accept()    BaseServer.verify_request()      BaseServer.process_request()        BaseServer.process_request()          BaseServer.finish_request(request, client_address)            BaseServer.RequestHandlerClass()              BaseRequestHandler.__init__(request)                BaseRequestHandler.request                BaseRequestHandler.client_address = client_address                StreamRequestHandler.setup()                  StreamRequestHandler.connection = StreamRequestHandler.request                  StreamRequestHandler.rfile                  StreamRequestHandler.wfile                BaseRequestHandler.handle()                StreamRequestHandler.finsih()                  StreamRequestHandler.wfile.close()                  StreamRequestHandler.rfile.close()          BaseServer.shutdown_request(request)            TCPServer.shutdown()              request.shutdown()            TCPServer.close_request(request)              request.close()      TCPServer.shutdown_request(request)        TCPServer.shutdown(request)          request.shutdown()        TCPServer.close_request(request)          request.close()

最早關于介紹BaseServer的時候,我們知道python對BaseServer設計的時候,預留了可用于Mixin擴展多線程或多進程的接口。mixin通過復寫父類的parse_request方法實現。

ThreadingMixIn
ThreadingMixIn 類實現了多線程的方式,它只有兩個方法,分別是process_request和 process_request_thread方法。多進程的方式是ForkingMixIn,暫且略過。

process_requestdef process_request(self, request, client_address):  t = threading.Thread(target = self.process_request_thread,             args = (request, client_address))  t.daemon = self.daemon_threads  t.start()

process_request方法復寫了父類的此方法。以此為接口入口,對每一個請求,調用Thread開啟一個新的線程。每一個線程都綁定process_request_thread方法。

process_request_thread  def process_request_thread(self, request, client_address):    try:      self.finish_request(request, client_address)      self.shutdown_request(request)    except:      self.handle_error(request, client_address)      self.shutdown_request(request)

process_request_thread方法和BaseServer里的parse_request幾乎一樣。只不過是多線程的方式調用。

使用的時候,通過多繼承調用接口,例如:

class ThreadingTCPServer(ThreadingMixIn, TCPServer):   pass

具體的調用過程如下:

ThreadingMixIn -- TCPServer - StreamRequestHandler__init__(server_address, RequestHandlerClass):   BaseServer.server_address  BaseServer.RequestHandlerClass  TCPServer.socket = socket.socket(self.address_family, self.socket_type)  TCPServer.server_bind()  TCPServer.server_activate()serve_forever():   select()   BaseServer._handle_request_noblock()    TCPServer.get_request() -> request, client_addres      socket.accept()    BaseServer.verify_request()      BaseServer.process_request()        ThreadingMixIn.process_request()          t = threading.Thread(target = ThreadingMixIn.process_request_thread)          ThreadingMixIn.process_request_thread            BaseServer.finish_request(request, client_address)              BaseServer.RequestHandlerClass()                BaseRequestHandler.__init__(request)                  BaseRequestHandler.request                  BaseRequestHandler.client_address = client_address                  StreamRequestHandler.setup()                    StreamRequestHandler.connection = StreamRequestHandler.request                    StreamRequestHandler.rfile                    StreamRequestHandler.wfile                  BaseRequestHandler.handle()                  StreamRequestHandler.finsih()                    StreamRequestHandler.wfile.close()                    StreamRequestHandler.rfile.close()            BaseServer.shutdown_request(request)              TCPServer.shutdown()                request.shutdown()              TCPServer.close_request(request)                request.close()      TCPServer.shutdown_request(request)        TCPServer.shutdown(request)          request.shutdown()        TCPServer.close_request(request)          request.close()
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 舞阳县| 临湘市| 宁国市| 湛江市| 淮阳县| 砚山县| 稻城县| 陵川县| 云龙县| 谢通门县| 永宁县| 天峨县| 达州市| 富民县| 三亚市| 赣榆县| 玛多县| 宣恩县| 丹寨县| 樟树市| 青川县| 司法| 晋城| 郯城县| 普宁市| 佛教| 江西省| 会同县| 松江区| 大冶市| 泸溪县| 措勤县| 惠安县| 赤水市| 彰化市| 嘉兴市| 新竹市| 玉山县| 威信县| 大理市| 道孚县|