從SocketServer 講起
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
整個(gè)模塊的結(jié)構(gòu)大概是這樣的熄攘,由BaseServer衍生出TCPServer补鼻,UDPServer胀葱,然后以此為基類,后續(xù)還有HTTPServer(SocketServer.TCPServer)唇牧,class WSGIServer(HTTPServer)罕扎,但入口都是接下去要說的SockerServer中的一些類。
BaseServer 有以下的一些方法
Methods for the caller:
- __init__(server_address, RequestHandlerClass)
- serve_forever(poll_interval=0.5)
- shutdown()
- handle_request() # if you do not use serve_forever()
- fileno() -> int # for select()
Methods that may be overridden:
- server_bind()
- server_activate()
- get_request() -> request, client_address
- handle_timeout()
- verify_request(request, client_address)
- server_close()
- process_request(request, client_address)
- shutdown_request(request)
- close_request(request)
- handle_error()
Methods for derived classes:
- finish_request(request, client_address)
Class variables that may be overridden by derived classes or
instances:
- timeout
- address_family
- socket_type
- allow_reuse_address
Instance variables:
- RequestHandlerClass
- socket
這其中有一系列鉤子方法留著給子類復(fù)寫以實(shí)現(xiàn)其特有的功能丐重。其中實(shí)現(xiàn)具體處理邏輯的為_handle_request_noblock方法
def _handle_request_noblock(self):
"""Handle one request, without blocking.
I assume that select.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 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)
get_request 需要子類來實(shí)現(xiàn)腔召,獲取request和address,而后由process_request 來處理扮惦,process_request 會依次調(diào)用finish_request 和shutdown_request,finish_request會調(diào)用RequestHandlerClass(需要傳入臀蛛,為具體處理的handler)。
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
# 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.
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 中崖蜜,會使用select 獲取需要處理的內(nèi)容浊仆,再調(diào)用上邊的_handle_request_noblock。
簡單的流程是這樣的豫领,BaseServer中定義了一些處理流程方面的東西抡柿,并沒有任何具體的處理,所有的處理流程等恐,都留給了子類洲劣。另外還有些上述沒提到的留給TCP 和UDPserver的方法,比如TCP的server_bind等不一一說了课蔬,具體看代碼囱稽。
Threading , Forking
這個(gè)模塊非常巧妙的使用mix-in class實(shí)現(xiàn)了Threading和Forking。
通過上面的分析我們知道二跋,核心的處理邏輯是process_request方法战惊,以多線程為例,如果我們要實(shí)現(xiàn)多線程扎即,其實(shí)只需要對這個(gè)方法做些改動即可吞获。
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
In addition, exception handling is done here.
"""
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
就是這么簡單的實(shí)現(xiàn),同樣的還有ForkingMixIn 铺遂, 這兩個(gè)mix-in class在后續(xù)很多地方都還會使用到衫哥,簡直是mix-in使用的完美范例茎刚。
handler
handler的基類是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()
def setup(self):
pass
def handle(self):
pass
def finish(self):
pass
而后還有兩個(gè)具體的實(shí)現(xiàn),StreamRequestHandler 和DatagramRequestHandler膛锭,分別用于TCP 和UDPServer中粮坞,也只是簡單實(shí)現(xiàn)了setup和finish蚊荣,核心handle方法留給子類實(shí)現(xiàn)。
入BaseHttpServer中莫杈,有一個(gè)BaseHTTPRequestHandler互例,針對http協(xié)議做了一系列處理,當(dāng)然筝闹,既然以base開頭媳叨,也只是為后續(xù)實(shí)現(xiàn)提供方便。如werkzeug.serving中的WSGIRequestHandler关顷,在繼承BaseHTTPRequestHandler的基礎(chǔ)上糊秆,做了一些修改,用于適配wsgi標(biāo)準(zhǔn)议双。如需要傳入application痘番,用于處理具體業(yè)務(wù)。