SocketServer
——網(wǎng)絡(luò)框架注意:SocketServer
在 python 3 中更名為 socketserver。 在將代碼轉(zhuǎn)換為 python 3 的版本時(shí),2to3 工具會(huì)自動(dòng)進(jìn)行導(dǎo)入適配。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名、虛擬空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、兩當(dāng)網(wǎng)站維護(hù)、網(wǎng)站推廣。
源碼:Lib/SocketServer.py
SocketServer 模塊簡(jiǎn)化了編寫網(wǎng)絡(luò)服務(wù)器應(yīng)用的步驟。它有四個(gè)具體的基礎(chǔ)服務(wù)器類:
class SocketServer.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
該類使用 TCP 網(wǎng)絡(luò)協(xié)議,在客戶端和服務(wù)器之間提供持續(xù)的流式數(shù)據(jù)。如果 bind_and_activate 為真,則構(gòu)造方法會(huì)自動(dòng)調(diào)用 server_bind() 和 server_activate() 方法。其余參數(shù)傳給基類 BaseServer。
class SocketServer.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
該類使用數(shù)據(jù)報(bào)文,而且報(bào)文包是離散的;在數(shù)據(jù)傳輸過(guò)程中,包到達(dá)的次序可能會(huì)錯(cuò)亂,或者出現(xiàn)丟失的情況。類參數(shù)和 TCPServer 一樣。
class SocketServer.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True) class SocketServer.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)
這兩個(gè)類使用得不如前兩個(gè)類頻繁,其用法類似,只是采用的是 Unix 域下的 sockets;它們不能在非 Unix 平臺(tái)上使用。類參數(shù)和 TCPServer 一樣。
以上四個(gè)類均采用同步方式處理網(wǎng)絡(luò)請(qǐng)求,即在處理下一個(gè)請(qǐng)求之前必須先處理完本次請(qǐng)求。如果請(qǐng)求耗時(shí)很長(zhǎng),比如計(jì)算量大,或數(shù)據(jù)太多引起客戶端處理慢等等,(同步方式)就不太合適了。解決的辦法是創(chuàng)建獨(dú)立的進(jìn)程或者線程用來(lái)應(yīng)對(duì)每個(gè)請(qǐng)求;mix-in 類 ForkingMixIn 和 ThreadIingMixin 可以支持這種異步行為。
創(chuàng)建一個(gè)服務(wù)器需要經(jīng)歷幾個(gè)步驟。首先,你要寫一個(gè)請(qǐng)求解析類,繼承自基類 BaseRequestHandler,同時(shí)改寫基類的 handle() 方法;這個(gè)方法會(huì)處理進(jìn)入服務(wù)器的每一個(gè)請(qǐng)求。第二步,你必須創(chuàng)建一個(gè)服務(wù)器類的對(duì)象,將服務(wù)器地址和請(qǐng)求解析類傳遞給該對(duì)象。之后調(diào)用服務(wù)器對(duì)象的 handle_request() 或者 server_forever() 方法處理一個(gè)或者多個(gè)請(qǐng)求。最后,調(diào)用 server_close() 方法關(guān)閉 socket。
若想繼承基類 ThreadingMixIn 完成多線程連接行為,你需要顯式地聲明線程在遇到突然關(guān)閉時(shí)如何處理。ThreadingMixIn 類有一個(gè)名為 daemon_threads 的屬性,表示線程如果終止,服務(wù)器是否應(yīng)該等待。如果你希望線程自動(dòng)處理,則必須顯式設(shè)置該標(biāo)志;默認(rèn)情況下,其值為 False,表示只有當(dāng)所有 ThreadingMixIn 創(chuàng)建的線程退出,Python 才會(huì)退出。
無(wú)論采用何種類型的網(wǎng)絡(luò)協(xié)議,服務(wù)器類都有相同的外部方法和屬性。
繼承的關(guān)系表格中有 5 個(gè)類,其中四種類型代表四個(gè)同步方式的服務(wù)器類。
+------------+ | BaseServer | +------------+ | v +-----------+ +------------------+ | TCPServer |------->| UnixStreamServer | +-----------+ +------------------+ | v +-----------+ +--------------------+ | UDPServer |------->| UnixDatagramServer | +-----------+ +--------------------+
注意 UnixDatagramServer 繼承自 UDPServer,而不是 UnixStreamServer——IP 和 Unix 流式服務(wù)器之間的唯一區(qū)別是地址族,兩個(gè) Unix 服務(wù)器使用相同的地址族。
class SocketServer.ForkingMixIn class SocketServer.ThreadingMixIn
每種類型的服務(wù)器都可以使用 mix-in 類創(chuàng)建多進(jìn)程或者多線程。例如下面的例子,創(chuàng)建一個(gè) ThreadingUDPServer 類:
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
注意,mix-in 類在前面,因?yàn)樗鼤?huì)重寫 UDPServer 中的一個(gè)方法。設(shè)置不同屬性也可以修改底層服務(wù)器的行為。
以下 ForkingMixIn 和 Forking 類只能在 POSIX 平臺(tái)上使用,支持 fork()。
class SocketServer.ForkingTCPServer class SocketServer.ForkingUDPServer class SocketServer.ThreadingTCPServer class SocketServer.ThreadingUDPServer
這四個(gè)類是預(yù)定義的 mix-in 類。
為給客戶端提供服務(wù),你必須從 BaseRequestHandler 類中派生子類,并重寫 handle() 方法。之后就可以通過(guò)合并某種類型的服務(wù)器與 BaseRequestHandler 子類來(lái)提供該類型的服務(wù)。報(bào)文服務(wù)和流式服務(wù)的請(qǐng)求解析類肯定是不同的。你可以繼承 StreamRequestHandler 或者 DatagramRequestHandler 類來(lái)隱藏這種差異。
當(dāng)然,你也可以自主發(fā)揮。比如,如果服務(wù)在內(nèi)存中的狀態(tài)可以被不同的請(qǐng)求修改,而子進(jìn)程的修改如果根本到不了父進(jìn)程的初始狀態(tài)并傳給子進(jìn)程,那么創(chuàng)建一個(gè)服務(wù)器的子進(jìn)程毫無(wú)意義。在這種情況下,你可以創(chuàng)建一個(gè)服務(wù)器的子線程,但為保證共享數(shù)據(jù)的完整性,可能需要加鎖。
另一個(gè)方面,如果你創(chuàng)建的一個(gè) HTTP 服務(wù)器,其所有數(shù)據(jù)都存在外部媒介(例如文件系統(tǒng))上,那么同步服務(wù)器在解析一個(gè)因客戶端接收數(shù)據(jù)慢導(dǎo)致耗時(shí)很長(zhǎng)的請(qǐng)求時(shí),就基本上只能“耗”在該服務(wù)上,兩耳不聞窗外事了。這個(gè)時(shí)候,創(chuàng)建一個(gè)子線程或者子進(jìn)程就很合適。
某些情況下,基于請(qǐng)求數(shù)據(jù),將請(qǐng)求的一部分內(nèi)容作同步處理,而將剩余部分放在子進(jìn)程中處理是可以的。可以創(chuàng)建一個(gè)同步服務(wù)器,而在 handle() 方法中 fork 一個(gè)子進(jìn)程完成上述動(dòng)作。
在一個(gè)既不支持多線程也不支持 fork 的環(huán)境下(或者在特定環(huán)境下,它們的代價(jià)都太大或者不合適),解析多個(gè)同時(shí)接收的請(qǐng)求的另一種辦法是維持一張顯式的表,表中記錄部分完成的請(qǐng)求,通過(guò) select() 方法來(lái)決定哪一個(gè)是即將工作的請(qǐng)求(或者需要解析新請(qǐng)求)。這對(duì)于每個(gè)客戶端可能會(huì)長(zhǎng)時(shí)間連接的流式服務(wù)尤其重要(前提是多線程或者多進(jìn)程不能使用)。可以去看看 asyncore 模塊,里面提到另一種方法來(lái)處理這種情況。
class SocketServer.BaseServer(server_address, RequestHandlerClass)
BaseServer 是模塊里所有服務(wù)器對(duì)象的父類。它定義了以下接口,但是其中的絕大部分的方法都不需要實(shí)現(xiàn),因?yàn)樗鼈冊(cè)谧宇惱锒紝?shí)現(xiàn)過(guò)了。需要兩個(gè)參數(shù),分別存在 server_address 和 RequestHandlerClass 屬性里。
fileno()
獲取服務(wù)器正在監(jiān)聽(tīng)的 socket 文件描述符。該方法最常用的做法是將返回值傳給 select.select() 方法,允許在同一個(gè)進(jìn)程中監(jiān)聽(tīng)多個(gè)服務(wù)器。
handle_request()
處理單一請(qǐng)求。這個(gè)函數(shù)按順序調(diào)用以下方法:get_request(), verify_request() 和 process_request()。如果用戶提供的請(qǐng)求解析類 handle() 方法拋出了異常,則服務(wù)器會(huì)調(diào)用 handle_error() 方法。如果在 timeout 秒內(nèi)沒(méi)有收到請(qǐng)求,則會(huì)調(diào)用 handle_timeout() 方法,同時(shí) handle_request() 返回。
serve_forever(poll_interval=0.5
解析請(qǐng)求,直至接收到一個(gè)顯示的 shutdown() 請(qǐng)求為止。每隔 poll_interval 秒會(huì)檢查一下是否收到 shutdown 請(qǐng)求。忽略 timeout 屬性。如果你需要進(jìn)行周期性的任務(wù),請(qǐng)?jiān)诹硪粋€(gè)線程里執(zhí)行。
shutdown()
告訴 serve_forever() 停止循環(huán),并等待 serve_forever() 停止之后才返回。
server_close()
清理服務(wù)器。可以被子類改寫。
address_family
服務(wù)器的 socket 所屬的協(xié)議族。常用值為 socket.AF_INET 和 socket.AF_UNIX
RequestHandlerClass
用戶提供的請(qǐng)求解析類;每個(gè)請(qǐng)求都會(huì)創(chuàng)建一個(gè)解析類對(duì)象。
server_address
服務(wù)器正在監(jiān)聽(tīng)的地址。地址值的格式取決于協(xié)議族;參考 socket 模塊的文檔以獲取更多詳細(xì)信息。因特網(wǎng)協(xié)議中,服務(wù)器地址是一個(gè)二元組,它包含指定的地址字符串和一個(gè)整型端口號(hào):例如 ( '127.0.0.1',80)
socket
服務(wù)器監(jiān)聽(tīng)請(qǐng)求時(shí)使用的 socket 對(duì)象
服務(wù)器類支持以下類屬性:
allow_resue_address
無(wú)論服務(wù)器是否允許地址重用,該值默認(rèn)為 False,可以在子類中修改。
request_queue_size
請(qǐng)求隊(duì)列的大小。如果處理單一請(qǐng)求時(shí)間很長(zhǎng),則當(dāng)服務(wù)器忙的時(shí)候,任何到達(dá)的請(qǐng)求會(huì)進(jìn)入到一個(gè)隊(duì)列中,直到個(gè)數(shù)達(dá)到 request_queue_size。一旦隊(duì)列滿了,那么后來(lái)的請(qǐng)求會(huì)收到 "Connection denied" 的錯(cuò)誤回饋。默認(rèn)值通常是 5,但是可以在子類進(jìn)行修改。
socket_type
服務(wù)器使用的 socket 類型;通常取 socket.SOCK_STREAM 和 socket.SOCK_DGRAM
timeout
超時(shí)時(shí)長(zhǎng),單位是秒,如果不需要超時(shí)設(shè)置,則為 None。如果 handle_request() 在超時(shí)時(shí)段內(nèi)沒(méi)有收到請(qǐng)求,則會(huì)調(diào)用 handle_timeout() 方法。
有幾個(gè)服務(wù)器方法可以在子類中(如 TCPServer) 中改寫;這些方法對(duì)于服務(wù)器對(duì)象的使用者而言是沒(méi)有什么用處的。
finish_request()
創(chuàng)建 RequestHandlerClass 對(duì)象并真正處理請(qǐng)求,調(diào)用解析類 handle() 的方法。
get_request()
必須接受一個(gè) socket 請(qǐng)求,返回一個(gè)二元組,包括新的 socket 對(duì)象用于和客戶端通信以及客戶端地址
handle_error(request, client_address)
如果 RequestHandlerClass 對(duì)象的 handle() 函數(shù)拋出了異常,則會(huì)調(diào)用 handle_error()。handle_error 默認(rèn)行為是將異常調(diào)用棧打印到標(biāo)準(zhǔn)輸出終端上,并繼續(xù)解析下一個(gè)請(qǐng)求。
handle_timeout()
當(dāng) timeout 屬性不是 None,而是一個(gè)有效值,而經(jīng)過(guò) timeout 時(shí)間之后還是沒(méi)有收到請(qǐng)求時(shí),會(huì)調(diào)用這個(gè)函數(shù)。handle_timeout 的默認(rèn)行為是 fork 一個(gè)服務(wù)器的子進(jìn)程用于收集任何退出的子進(jìn)程狀態(tài),而在服務(wù)器的多個(gè)線程中,該方法什么也不做。
process_request(request, client_addresss)
調(diào)用 finish_request() 創(chuàng)建一個(gè) RequestHandlerClass 對(duì)象。如果需要,這個(gè)函數(shù)會(huì)創(chuàng)建一個(gè)新的進(jìn)程或者線程用于解析請(qǐng)求;ForkingMixIn 和 ThreadingMixIn 類會(huì)完成這個(gè)動(dòng)作。
server_activate()
由類的構(gòu)造方法調(diào)用,用于激活服務(wù)器。TCP 服務(wù)器里的 server_activate() 默認(rèn)只會(huì)調(diào)用 listen() 方法,用于監(jiān)聽(tīng)服務(wù)器的 socket 對(duì)象。該方法可以被子類改寫。
server_bind()
由類的構(gòu)造方法調(diào)用,用于將 socket 對(duì)象綁定到指定地址上。該方法可以被子類改寫。
verify_request(request, client_address)
必須返回一個(gè)布爾值;如果值為 True,則處理請(qǐng)求,否則拒絕處理。verify_request 可以被子類改寫,憑借該方法,服務(wù)器可以實(shí)現(xiàn)訪問(wèn)控制。該方法默認(rèn)返回 True。
class SocketServer.BaseRequestHandler
它是所有請(qǐng)求解析類對(duì)象的父類。有以下接口。請(qǐng)求解析類的子類必須實(shí)現(xiàn) handle() 方法,可以改寫其他方法。每個(gè)請(qǐng)求都會(huì)創(chuàng)建一個(gè)子類對(duì)象。
setup()
在 handle() 函數(shù)之前調(diào)用,用于初始化行為。默認(rèn)什么也不做
handle()
這個(gè)函數(shù)必須完成所有期望的工作,為請(qǐng)求提供服務(wù)。默認(rèn)什么也不做。handle() 可以使用幾個(gè)實(shí)例屬性;請(qǐng)求實(shí)例 self.request;客戶端地址 self.client_address;服務(wù)器實(shí)例 self.server,以便訪問(wèn)服務(wù)器的信息。
報(bào)文服務(wù)或者流式服務(wù)的 self.request 類型是不一樣的。對(duì)于流式服務(wù),self.request 是一個(gè) socket 對(duì)象;而報(bào)文服務(wù),self.request 是一對(duì)字符串加 socket。
finish()
在 handle() 方法調(diào)用之后執(zhí)行所有清理操作。默認(rèn)什么也不做。如果 setup() 拋出異常,那么這個(gè)函數(shù)不會(huì)被執(zhí)行。
class SocketServer.
StreamRequestHandler
class SocketServer.
DatagramRequestHandler
這些 BaseRequestHandler 的子類改寫 setup() 和 finish() 方法,同時(shí)提供了 self.rfile 和 self.wfile 屬性。self.rfile 是可讀的,用于獲取請(qǐng)求數(shù)據(jù);self.wfile 屬性是可寫的,用于提供數(shù)據(jù)給客戶端。
新聞名稱:python之SocketServer
文章地址:http://vcdvsql.cn/article0/pepsio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、App設(shè)計(jì)、網(wǎng)站改版、做網(wǎng)站、靜態(tài)網(wǎng)站、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)