asynchat
--- 異步套接字指令/響應(yīng)處理程序?
源代碼: Lib/asynchat.py
Deprecated since version 3.6, removed in version 3.12: The asynchat
module is deprecated
(see PEP 594 for details).
Please use asyncio
instead.
備注
該模塊僅為提供向后兼容。我們推薦在新代碼中使用 asyncio
。
此模塊在 asyncore
框架之上構(gòu)建,簡(jiǎn)化了異步客戶端和服務(wù)器并使得處理元素為以任意字符串結(jié)束或者為可變長(zhǎng)度的協(xié)議更加容易。 asynchat
定義了一個(gè)可以由你來(lái)子類化的抽象類 async_chat
,提供了 collect_incoming_data()
和 found_terminator()
等方法的實(shí)現(xiàn)。 它使用與 asyncore
相同的異步循環(huán),并且可以在通道映射中自由地混合 asyncore.dispatcher
和 asynchat.async_chat
這兩種類型的通道。 一般來(lái)說(shuō) asyncore.dispatcher
服務(wù)器通道在接收到傳入的連接請(qǐng)求時(shí)會(huì)生成新的 asynchat.async_chat
通道對(duì)象。
- class asynchat.async_chat?
這個(gè)類是
asyncore.dispatcher
的抽象子類。 對(duì)于實(shí)際使用的代碼你必須子類化async_chat
,提供有意義的collect_incoming_data()
和found_terminator()
方法。asyncore.dispatcher
的方法也可以被使用,但它們?cè)谙?響應(yīng)上下文中并不是全都有意義。與
asyncore.dispatcher
類似,async_chat
也定義了一組通過(guò)對(duì)select()
調(diào)用之后的套接字條件進(jìn)行分析所生成的事件。 一旦啟動(dòng)輪詢循環(huán)async_chat
對(duì)象的方法就會(huì)被事件處理框架調(diào)用而無(wú)須程序員方面做任何操作。兩個(gè)可被修改的類屬性,用以提升性能,甚至也可能會(huì)節(jié)省內(nèi)存。
- ac_in_buffer_size?
異步輸入緩沖區(qū)大小 (默認(rèn)為
4096
)。
- ac_out_buffer_size?
異步輸出緩沖區(qū)大小 (默認(rèn)為
4096
)。
與
asyncore.dispatcher
不同,async_chat
允許你定義一個(gè) FIFO 隊(duì)列 producers。 其中的生產(chǎn)者只需要一個(gè)方法more()
,該方法應(yīng)當(dāng)返回要在通道上傳輸?shù)臄?shù)據(jù)。 生產(chǎn)者通過(guò)讓其more()
方法返回空字節(jié)串對(duì)象來(lái)表明其處于耗盡狀態(tài) (意即 它已不再包含數(shù)據(jù))。 此時(shí)async_chat
對(duì)象會(huì)將該生產(chǎn)者從隊(duì)列中移除并開始使用下一個(gè)生產(chǎn)者,如果有下一個(gè)的話。 當(dāng)生產(chǎn)者隊(duì)列為空時(shí)handle_write()
方法將不執(zhí)行任何操作。 你要使用通道對(duì)象的set_terminator()
方法來(lái)描述如何識(shí)別來(lái)自遠(yuǎn)程端點(diǎn)的入站傳輸?shù)慕Y(jié)束或是重要的中斷點(diǎn)。要構(gòu)建一個(gè)可用的
async_chat
子類,你的輸入方法collect_incoming_data()
和found_terminator()
必須要處理通道異步接收的數(shù)據(jù)。 這些參數(shù)的描述見下文。
- async_chat.close_when_done()?
將
None
推入生產(chǎn)者隊(duì)列。 當(dāng)此生產(chǎn)者被彈出隊(duì)列時(shí)它將導(dǎo)致通道被關(guān)閉。
- async_chat.collect_incoming_data(data)?
調(diào)用時(shí)附帶 data,其中包含任意數(shù)量的已接收數(shù)據(jù)。 必須被重載的默認(rèn)方法將引發(fā)一個(gè)
NotImplementedError
異常。
- async_chat.discard_buffers()?
在緊急情況下此方法將丟棄輸入和/或輸出緩沖區(qū)以及生產(chǎn)者隊(duì)列中的任何數(shù)據(jù)。
- async_chat.found_terminator()?
當(dāng)輸入數(shù)據(jù)流能匹配
set_terminator()
所設(shè)定的終結(jié)條件時(shí)會(huì)被調(diào)用。 必須被重載的默認(rèn)方法將引發(fā)一個(gè)NotImplementedError
異常。 被緩沖的輸入數(shù)據(jù)應(yīng)當(dāng)可以通過(guò)實(shí)例屬性來(lái)獲取。
- async_chat.get_terminator()?
返回通道的當(dāng)前終結(jié)器。
- async_chat.push(data)?
將數(shù)據(jù)推入通道的隊(duì)列以確保其被傳輸。 要讓通道將數(shù)據(jù)寫到網(wǎng)絡(luò)中你只需要這樣做就足夠了,雖然以更復(fù)雜的方式使用你自己的生產(chǎn)者也是有可能的,例如為了實(shí)現(xiàn)加密和分塊。
- async_chat.push_with_producer(producer)?
獲取一個(gè)生產(chǎn)者對(duì)象并將其加入到與通道相關(guān)聯(lián)的生產(chǎn)者隊(duì)列中。 當(dāng)所有當(dāng)前已推入的生產(chǎn)者都已被耗盡時(shí)通道將通過(guò)調(diào)用其
more()
方法來(lái)耗用此生產(chǎn)者的數(shù)據(jù)并將數(shù)據(jù)發(fā)送至遠(yuǎn)程端點(diǎn)。
- async_chat.set_terminator(term)?
設(shè)置可在通道上被識(shí)別的終結(jié)條件。
term
可以是三種類型值中的任意一種 ,對(duì)應(yīng)于處理入站協(xié)議數(shù)據(jù)的三種不同方式。term
描述
string
當(dāng)在輸入流中發(fā)現(xiàn)該字符串時(shí)將會(huì)調(diào)用
found_terminator()
integer
當(dāng)接收到指定數(shù)量的字符時(shí)將會(huì)調(diào)用
found_terminator()
None
通道會(huì)不斷地持續(xù)收集數(shù)據(jù)
請(qǐng)注意終結(jié)器之后的任何數(shù)據(jù)將可在
found_terminator()
被調(diào)用后由通道來(lái)讀取。
asynchat 示例?
下面的例子片段顯示了如何通過(guò) async_chat
來(lái)讀取 HTTP 請(qǐng)求。 Web 服務(wù)器可以為每個(gè)入站的客戶端連接創(chuàng)建 http_request_handler
對(duì)象。 請(qǐng)注意在初始時(shí)通道終結(jié)器會(huì)被設(shè)置為匹配 HTTP 標(biāo)頭末尾的空行,并且會(huì)用一個(gè)旗標(biāo)來(lái)指明標(biāo)頭正在被讀取。
一旦完成了標(biāo)頭的讀取,如果請(qǐng)求類型為 POST (表明輸入流中存在更多的數(shù)據(jù)) 則會(huì)使用 Content-Length:
標(biāo)頭來(lái)設(shè)置一個(gè)數(shù)值終結(jié)器以從通道讀取適當(dāng)數(shù)量的數(shù)據(jù)。
一旦完成了對(duì)所有相關(guān)輸入的處理,將會(huì)在設(shè)置通道終結(jié)器為 None
以確保忽略掉 Web 客戶端所發(fā)送的任何無(wú)關(guān)數(shù)據(jù)之后調(diào)用 handle_request()
方法。
import asynchat
class http_request_handler(asynchat.async_chat):
def __init__(self, sock, addr, sessions, log):
asynchat.async_chat.__init__(self, sock=sock)
self.addr = addr
self.sessions = sessions
self.ibuffer = []
self.obuffer = b""
self.set_terminator(b"\r\n\r\n")
self.reading_headers = True
self.handling = False
self.cgi_data = None
self.log = log
def collect_incoming_data(self, data):
"""Buffer the data"""
self.ibuffer.append(data)
def found_terminator(self):
if self.reading_headers:
self.reading_headers = False
self.parse_headers(b"".join(self.ibuffer))
self.ibuffer = []
if self.op.upper() == b"POST":
clen = self.headers.getheader("content-length")
self.set_terminator(int(clen))
else:
self.handling = True
self.set_terminator(None)
self.handle_request()
elif not self.handling:
self.set_terminator(None) # browsers sometimes over-send
self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
self.handling = True
self.ibuffer = []
self.handle_request()