首頁  >  文章  >  後端開發  >  Python中asyncore非同步模組的用法及實作httpclient

Python中asyncore非同步模組的用法及實作httpclient

高洛峰
高洛峰原創
2017-03-01 14:20:012066瀏覽

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 &#39;%04i <--&#39;%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 &#39;<-- %04i&#39;%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 &#39;--> %04i&#39;%sent
    self.receiver.from_remote_buffer = self.receiver.from_remote_buffer[sent:]

  def handle_close(self):
    self.close()
    self.receiver.close()

if __name__==&#39;__main__&#39;:
  import optparse
  parser = optparse.OptionParser()

  parser.add_option(
    &#39;-l&#39;,&#39;--local-ip&#39;,
    dest=&#39;local_ip&#39;,default=&#39;127.0.0.1&#39;,
    help=&#39;Local IP address to bind to&#39;)
  parser.add_option(
    &#39;-p&#39;,&#39;--local-port&#39;,
    type=&#39;int&#39;,dest=&#39;local_port&#39;,default=80,
    help=&#39;Local port to bind to&#39;)
  parser.add_option(
    &#39;-r&#39;,&#39;--remote-ip&#39;,dest=&#39;remote_ip&#39;,
    help=&#39;Local IP address to bind to&#39;)
  parser.add_option(
    &#39;-P&#39;,&#39;--remote-port&#39;,
    type=&#39;int&#39;,dest=&#39;remote_port&#39;,default=80,
    help=&#39;Remote port to bind to&#39;)
  options, args = parser.parse_args()

  forwarder(options.local_ip,options.local_port,options.remote_ip,options.remote_port)
  asyncore.loop()

更多Python中asyncore異步模組的用法及實作httpclient相關文章請關注PHP中文網!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn