asyncore即是一個非同步的socket封裝,特別是dispatcher類別中包含了很多非同步呼叫的socket操作方法,非常犀利,下面我們就來講解Python中asyncore異步模組的用法及實現httpclient的實例
基礎
這個模組是socket的非同步實現,讓我們先來熟悉模組中的一些類別和方法:
1.asyncore.loop
輸入一個輪詢循環直到通過計數或開啟的通道已關閉。
2.asyncore.dispatcher
dispatcher類別是一個底層socket類別的包裝物件。要使它更有用, 它有一部分事件處理方法被非同步循環呼叫。否則它就是一個標準的非阻塞socket物件。
底層的事件在特定事件或特定的連接狀態告訴非同步循環,某些高級事件發生了。例如, 我們要求一個socket連接到另一個主機。
(1)handle_connect() 第一次讀取或寫入事件。
(2)handle_close() 讀取事件沒有資料可用。
(3)handle_accept 讀事件監聽一個socket。
(4)handle_read
在非同步循環察覺到通道呼叫read()時呼叫。
(5)handle_write
在非同步循環偵測到一個可寫的socket可以寫的時候呼叫。這種方法經常實現緩衝性能。例如
def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
(6)handle_expt
當有(OOB)資料套接字連接。這幾乎永遠不會發生,因為OOB精細地支持和很少使用。
(7)handle_connect
當socket建立一個連線時呼叫。
(8)handle_close
當socket連線關閉時呼叫。
(9)handle_error
當引發一個例外並沒有其他處理時呼叫。
(10)handle_accept
當本機監聽通道與遠端建立連線(被動連線)時呼叫。
(11)readable
每次在非同步循環決定是否新增一個通道socket到讀取事件清單時呼叫,預設都為True。
(12)writable
每次在非同步循環決定是否新增一個通道socket到寫事件清單時呼叫, 預設為True。
(13)create_socket
與建立標準socket的時候相同。
(14)connect
與標準socket的連接埠設定是相同, 接受一個元組第一個參數為主機位址,第二個參數是埠號。
(15)send
向遠端socket發送資料。
(16)recv
從遠端socket讀取最多buffer_size的資料。一個空的字串意味著從另一端通道已關閉。
(17)listen
監聽socket連線。
(18)bind
將socket綁定到位址。
(19)accept
接受一個連線, 必須綁定到一個socket和監聽位址。
(20)close
關閉socket。
3.asyncore.dispatcher_with_send
#dispatcher子類別加入了簡單的緩衝輸出功能用於簡單的客戶,更複雜的使用asynchat.async_chat。
4.asyncore.file_dispatcher
file_dispatcher需要一個檔案描述子或檔案物件地圖以及一個可選的參數,包裝,使用調查()或循環()函數。如果提供一個檔案物件或任何fileno()方法,該方法將呼叫和傳遞到file_wrapper建構子。可用性:UNIX。
5.asyncore.file_wrapper
file_wrapper需要一個整數檔案描述子並呼叫os.dup()複製處理,這樣原來的處理可能是獨立於file_wrapper關閉。這個類別實作足夠的方法來模擬一個套接字使用file_dispatcher類別。可用性:UNIX。
asyncore 實例
1.一個http client的實作。
import socket import asyncore class Client(asyncore.dispatcher): def __init__(self, host, path): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((host, 80)) self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path 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 = Client('www.python.org', '/') asyncore.loop()
伺服器接受連線與指派任務
import socket 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(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_add() self.bind((host, port)) self.listen(5) def handle_accept(self): pair = self.accept() if pair is not None: sock, addr = pair print 'Incoming connection from %s' % repr(addr) handler = EchoHandler(sock) server = EchoServer('localhost', 8080) asyncore.loop()
2.利用asyncore的埠對映(埠轉送)
import socket,asyncore class forwarder(asyncore.dispatcher): def __init__(self, ip, port, remoteip,remoteport,backlog=5): asyncore.dispatcher.__init__(self) self.remoteip=remoteip self.remoteport=remoteport self.create_socket(socket.AF_INET,socket.SOCK_STREAM) self.set_reuse_addr() self.bind((ip,port)) self.listen(backlog) def handle_accept(self): conn, addr = self.accept() # print '--- Connect --- ' sender(receiver(conn),self.remoteip,self.remoteport) class receiver(asyncore.dispatcher): def __init__(self,conn): asyncore.dispatcher.__init__(self,conn) self.from_remote_buffer='' self.to_remote_buffer='' self.sender=None def handle_connect(self): pass def handle_read(self): read = self.recv(4096) # print '%04i -->'%len(read) self.from_remote_buffer += read def writable(self): return (len(self.to_remote_buffer) > 0) def handle_write(self): sent = self.send(self.to_remote_buffer) # print '%04i <--'%sent self.to_remote_buffer = self.to_remote_buffer[sent:] def handle_close(self): self.close() if self.sender: self.sender.close() class sender(asyncore.dispatcher): def __init__(self, receiver, remoteaddr,remoteport): asyncore.dispatcher.__init__(self) self.receiver=receiver receiver.sender=self self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((remoteaddr, remoteport)) def handle_connect(self): pass def handle_read(self): read = self.recv(4096) # print '<-- %04i'%len(read) self.receiver.to_remote_buffer += read def writable(self): return (len(self.receiver.from_remote_buffer) > 0) def handle_write(self): sent = self.send(self.receiver.from_remote_buffer) # print '--> %04i'%sent self.receiver.from_remote_buffer = self.receiver.from_remote_buffer[sent:] def handle_close(self): self.close() self.receiver.close() if __name__=='__main__': import optparse parser = optparse.OptionParser() parser.add_option( '-l','--local-ip', dest='local_ip',default='127.0.0.1', help='Local IP address to bind to') parser.add_option( '-p','--local-port', type='int',dest='local_port',default=80, help='Local port to bind to') parser.add_option( '-r','--remote-ip',dest='remote_ip', help='Local IP address to bind to') parser.add_option( '-P','--remote-port', type='int',dest='remote_port',default=80, help='Remote port to bind to') options, args = parser.parse_args() forwarder(options.local_ip,options.local_port,options.remote_ip,options.remote_port) asyncore.loop()
更多Python中asyncore異步模組的用法及實作httpclient相關文章請關注PHP中文網!