緣于要做個http代理服務(wù)器的需求,開始琢磨SocketServer類,看看其有多優(yōu)秀
BaseServer: 定義基礎(chǔ)服務(wù)器接口,這些功能接口提供給子類繼承。同時提供服務(wù)處理的骨架
serve_forever() 循環(huán)調(diào)用 handle_request()
handle_request() 調(diào)用子類的get_request() ,在tcpServer時實則進行accept()應(yīng)答; 驗證處理 verify_request();
最終處理請求 process_request(),
verify_request() 虛函數(shù)
process_request() 虛函數(shù),這個函數(shù)并沒有直接在BaseServer的子類TcpServer中被重載,而是在TcpServer的派生類中通過另一個父類來實
現(xiàn),比如 ThreadingTCPServer的基類ThreadingMixIn.process_request()實現(xiàn)了此功能函數(shù)
finish_request(request, client_address) 執(zhí)行一次完整的socket數(shù)據(jù)讀入處理,如果是ThreadMixInTcpServer產(chǎn)生的request,這個方法內(nèi)必須實行循環(huán)讀取socket數(shù)據(jù),直到socket關(guān)閉。(此處 request 就是 socket對象)
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
在finish_request里面便將讀取socket數(shù)據(jù)的任務(wù)扔給了RequestHandler去處理了,代碼可以跳過去看了
##---------------------------------------------
TcpServer: tcp服務(wù)器
__init__(self, server_address, RequestHandlerClass) 需要提供服務(wù)偵聽地址和請求處理類對象
server_bind() 綁定服務(wù)器地址
server_activate() 激活服務(wù)器
server_close() 關(guān)閉服務(wù)器
fileno() 返回服務(wù)器socket的句柄fd編號
get_request() 接收應(yīng)答accept()
close_request(request) 關(guān)閉socket,request即為socket對象
三種輸出處理方式: 阻塞方式、線程處理(ThreadingMixIn)、進程處理(ForkingMixIn)
ThreadingMixIn: 線程模型
process_request( request, client_address) 為請求的鏈接創(chuàng)建新的線程,在創(chuàng)建線程時直接指定線程入口和參數(shù):
import threading
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
if self.daemon_threads:
t.setDaemon (1)
process_request_thread() 線程處理socket入口,負責(zé)接收數(shù)據(jù),代碼實現(xiàn)有點繞,看看代碼
def process_request_thread(self, request, client_address):
try:
self.finish_request(request, client_address)
self.close_request(request)
except:
self.handle_error(request, client_address)
self.close_request(request)
ThreadingMixIn
其實就是線程代理,還是調(diào)用finish_request()進入處理tcp數(shù)據(jù)的循環(huán),處理完成便close_request()。但是finish_request和close_request并未在ThreadingMinxIn內(nèi)定義,在哪里呢? 通過研讀ThreadingTcpServer,原來通過ThreadingTcpServer這個finish_request又跑回了BaseServer.finish_request()
ThreadingTCPServer(ThreadingMixIn, TCPServer) 裝配成線程池處理的tcp服務(wù)器
BaseRequestHandler: 請求處理基礎(chǔ)對象,提供統(tǒng)一的行為接口實現(xiàn)處理socket數(shù)據(jù)。 BaseRequestHandler比較好玩,在構(gòu)造函數(shù)內(nèi)完成了所有的操作,見代碼:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
try:
self.setup()
self.handle()
self.finish()
finally:
sys.exc_traceback = None # Help garbage collection
setup()對應(yīng)的子類會進行初始化處理
self.handle() 直接調(diào)用子類的處理函數(shù),可以參考 BaseHTTPRequestHandler(SocketServer.StreamRequestHandler)::handle()
StreamRequestHandler(BaseRequestHandler) 流式socket處理類
setup() 設(shè)置好socket對象和讀寫文件句柄 rfile/wfile
HTTPServer(SocketServer.TCPServer) http服務(wù)器
BaseHTTPRequestHandler(SocketServer.StreamRequestHandler) 流式的請求處理類
handle() 處理入口,在基類BaseRequestHandle()的構(gòu)造函數(shù)中直接調(diào)用
handle_one_request() 如果不是處理一次則返回false。接收一次socket數(shù)據(jù),解析parse_request(),調(diào)用對應(yīng)的do_xxx事件
python 的daemon線程:
如果一個進程的主線程運行完畢而子線程還在執(zhí)行的話,那么進程就不會退出,直到所有子線程結(jié)束為止,如何讓主線程結(jié)束的時候其他子線程也乖乖的跟老大撤退呢?那就要把那些不聽話的人設(shè)置為聽話的小弟,使用線程對象的setDaemon()方法,參數(shù)為bool型。True的話就代表你要聽話,我老大(主線程)扯呼,你也要跟著撤,不能拖后腿。如果是False的話就不用那么聽話了,老大允許你們將在外軍命有所不受的。需要注意的是setDaemon()方法必須在線程對象沒有調(diào)用start()方法之前調(diào)用,否則沒效果。