asyncore --- 異步socket處理器?
源碼: Lib/asyncore.py
3.6 版后已移除: 請使用 asyncio 替代。
注解
該模塊僅為提供向后兼容。我們推薦在新代碼中使用 asyncio 。
該模塊提供用于編寫異步套接字服務客戶端與服務端的基礎構件。
只有兩種方法讓單個處理器上的程序“同一時間完成不止一件事”。 多線程編程是最簡單和最流行的方法,但是還有另一種非常不同的技術,它可以讓你擁有多線程的幾乎所有優點,而無需實際使用多線程。 它僅僅在你的程序主要受 I/O 限制時有用,那么。 如果你的程序受處理器限制,那么先發制人的預定線程可能就是你真正需要的。 但是,網絡服務器很少受處理器限制。
如果你的操作系統在其 I/O 庫中支持 select() 系統調用(幾乎所有操作系統),那么你可以使用它來同時處理多個通信通道;在 I/O 正在“后臺”時進行其他工作。 雖然這種策略看起來很奇怪和復雜,特別是起初,它在很多方面比多線程編程更容易理解和控制。 asyncore 模塊為您解決了許多難題,使得構建復雜的高性能網絡服務器和客戶端的任務變得輕而易舉。 對于“會話”應用程序和協議,伴侶 asynchat 模塊是非常寶貴的。
這兩個模塊背后的基本思想是創建一個或多個網絡 通道 ,類的實例 asyncore.dispatcher 和 asynchat.async_chat 。 創建通道會將它們添加到全局映射中,如果你不為它提供自己的 映射 ,則由 loop() 函數使用。
一旦創建了初始通道,調用 loop() 函數將激活通道服務,該服務將一直持續到最后一個通道(包括在異步服務期間已添加到映射中的任何通道)關閉。
-
asyncore.loop([timeout[, use_poll[, map[, count]]]])? 進入一個輪詢循環,其在循環計數超出或所有打開的通道關閉后終止。 所有參數都是可選的。 count 形參默認為
None,導致循環僅在所有通道關閉時終止。 timeout 形參為適當的select()或poll()調用設置超時參數,以秒為單位; 默認值為30秒。 use_poll 形參,如果為 True ,則表示poll()應優先使用select()(默認為``False``)。map 形參是一個條目為所監視通道的字典。 當通道關閉時它們會被從映射中刪除。 如果省略 map,則會使用一個全局映射。 通道 (
asyncore.dispatcher,asynchat.async_chat及其子類的實例) 可以在映射中任意混合。
-
class
asyncore.dispatcher? dispatcher類是對低層級套接字對象的輕量包裝器。 要讓它更有用處,可以從異步循環調用一些事件處理方法。 在其他方面,它可以被當作是普通的非阻塞型套接字對象。在特定時間或特定連接狀態下觸發的低層級事件可通知異步循環發生了特定的高層級事件。 例如,如果我們請求了一個套接字以連接到另一臺主機,我們會在套接字首次變得可寫時得知連接已建立(在此刻你將知道可以向其寫入并預期能夠成功)。 包含的高層級事件有:
Event
描述
handle_connect()由首個讀取或寫入事件所包含
handle_close()由不帶可用數據的讀取事件引起
handle_accepted()由在監聽套接字上的讀取事件引起
在異步處理過程中,每個已映射通道的
readable()和writable()方法會被用來確定是否要將通道的套接字添加到已執行select()或poll()用于讀取和寫入事件的通道列表中。因此,通道事件的集合要大于基本套接字事件。 可以在你的子類中被重載的全部方法集合如下:
-
handle_read()? 當異步循環檢測到通道的套接字上的
read()調用將要成功時會被調用。
-
handle_write()? 當異步循環檢測到一個可寫套接字可以被寫入時會被調用。 通常此方法將實現必要的緩沖機制以保證運行效率。 例如:
def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
-
handle_expt()? 當一個套接字連接存在帶外(OOB)數據時會被調用。 這幾乎從來不會發生,因為 OOB 雖然受支持但很少被使用。
-
handle_connect()? 當活動打開方的套接字實際建立連接時會被調用。 可能會發送一條“歡迎”消息,或者向遠程端點發起協議協商等。
-
handle_close()? 當套接字關閉時會被調用。
-
handle_error()? 當一個異常被引發并且未獲得其他處理時會被調用。 默認版本將打印精簡的回溯信息。
-
handle_accept()? 當可以與發起對本地端點的
connect()調用的新遠程端點建立連接時會在偵聽通道(被動打開方)上被調用。 在 3.2 版中已被棄用;請改用handle_accepted()。3.2 版后已移除.
-
handle_accepted(sock, addr)? 當與發起對本地端點的
connect()調用的新遠程端點已建立連接時會在偵聽通道(被動打開方)上被調用。 sock 是可被用于在連接上發送和接收數據的 新建 套接字對象,而 addr 是綁定到連接另一端的套接字的地址。3.2 新版功能.
-
readable()? 每次在異步循環之外被調用以確定是否應當將一個通道的套接字添加到可能在其上發生讀取事件的列表中。 默認方法會簡單地返回
True,表示在默認情況下,所有通道都希望能讀取事件。
-
writable()? 每次在異步循環之外被調用以確定是否應當將一個通道的套接字添加到可能在其上發生寫入事件的列表中。 默認方法會簡單地返回
True,表示在默認情況下,所有通道都希望能寫入事件。
此外,每個通道都委托或擴展了許多套接字方法。 它們大部分都與其套接字的對應方法幾乎一樣。
-
create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM)? 這與普通套接字的創建相同,并會使用同樣的創建選項。 請參閱
socket文檔了解有關創建套接字的信息。在 3.3 版更改: family 和 type 參數可以被省略。
-
connect(address)? 與普通套接字對象一樣,address 是一個元組,它的第一個元素是要連接的主機,第二個元素是端口號。
-
send(data)? 將 data 發送到套接字的遠程端點。
-
recv(buffer_size)? 從套接字的遠程端點讀取至多 buffer_size 個字節。 讀到空字節串表明通道已從另一端被關閉。
請注意
recv()可能會引發BlockingIOError,即使select.select()或select.poll()報告套接字已準備好被讀取。
-
listen(backlog)? 偵聽與套接字的連接。 backlog 參數指明排入連接隊列的最大數量且至少應為 1;最大值取決于具體系統(通常為 5)。
-
bind(address)? 將套接字綁定到 address。 套接字必須尚未被綁定。 (address 的格式取決于具體的地址族 --- 請參閱
socket文檔了解更多信息。) 要將套接字標記為可重用的 (設置SO_REUSEADDR選項),請調用dispatcher對象的set_reuse_addr()方法。
-
accept()? 接受一個連接。 此套接字必須綁定到一個地址上并且偵聽連接。 返回值可以是
None或一個(conn, address)對,其中 conn 是一個可用來在此連接上發送和接收數據的 新的 套接字對象,而 address 是綁定到連接另一端套接字的地址。 當返回None時意味著連接沒有建立,在此情況下服務器應當忽略此事件并繼續偵聽后續的入站連接。
-
close()? 關閉套接字。 在此套接字對象上的后續操作都將失敗。 遠程端點將不再接收任何數據(在排入隊列的數據被清空之后)。 當套接字被垃圾回收時會自動關閉。
-
-
class
asyncore.dispatcher_with_send? dispatcher的一個添加了簡單緩沖輸出功能的子類,適用于簡單客戶端。 對于更復雜的用法請使用asynchat.async_chat。
-
class
asyncore.file_dispatcher? file_dispatcher 接受一個文件描述符或 file object 以及一個可選的 map 參數,并對其進行包裝以配合
poll()或loop()函數使用。 如果提供一個文件對象或任何具有fileno()方法的對象,其方法將被調用并傳遞給file_wrapper構造器。可用性: Unix。
-
class
asyncore.file_wrapper? file_wrapper 接受一個整數形式的文件描述符并調用
os.dup()來復制其句柄,以便原始句柄可以獨立于 file_wrapper 被關閉。 這個類實現了足夠的方法來模擬套接字以供file_dispatcher類來使用。可用性: Unix。
asyncore 示例基本 HTTP 客戶端?
下面是一個非?;镜?HTTP 客戶端,它使用了 dispatcher 類來實現套接字處理:
import asyncore
class HTTPClient(asyncore.dispatcher):
def __init__(self, host, path):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.connect( (host, 80) )
self.buffer = bytes('GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' %
(path, host), 'ascii')
def handle_connect(self):
pass
def handle_close(self):
self.close()
def handle_read(self):
print(self.recv(8192))
def writable(self):
return (len(self.buffer) > 0)
def handle_write(self):
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
client = HTTPClient('www.python.org', '/')
asyncore.loop()
asyncore 示例基本回顯服務器?
下面是一個基本的回顯服務器,它使用了 dispatcher 類來接受連接并將入站連接發送給處理程序:
import asyncore
class EchoHandler(asyncore.dispatcher_with_send):
def handle_read(self):
data = self.recv(8192)
if data:
self.send(data)
class EchoServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accepted(self, sock, addr):
print('Incoming connection from %s' % repr(addr))
handler = EchoHandler(sock)
server = EchoServer('localhost', 8080)
asyncore.loop()
