Pythonにおけるasyncore非同期モジュールの使い方とhttpclientを実現する例

6569 ワード

このモジュールはsocketの非同期実装であり、まずモジュールのいくつかのクラスと方法を熟知しましょう.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
ソケットが接続を作成すると呼び出されます.
(8)handle_close
ソケット接続が閉じたときに呼び出されます.
(9)handle_error
例外が発生して他の処理がない場合に呼び出されます.
(10)handle_accept
ローカルリスニングチャネルがリモート側と接続(パッシブ接続)されている場合に呼び出されます.
(11)readable
非同期ループがチャネルsocketを読み取りイベントリストに追加するかどうかを決定するたびに呼び出され、デフォルトはTrueです.
(12)writable
非同期ループがチャネルsocketを書き込みイベントリストに追加するかどうかを決定するたびに呼び出され、デフォルトはTrueです.
(13)create_socket
標準socketを作成したときと同じです.
(14)connect
標準socketのポート設定と同様に、1つのメタグループの最初のパラメータがホストアドレスであり、2番目のパラメータがポート番号であることを受け入れます.
(15)send
リモート側socketにデータを送信します.
(16)recv
リモート側socketから最大buffer_を読み込むsizeのデータ.空の文字列は、反対側のチャネルが閉じていることを意味します.
(17)listen
ソケット接続を傍受します.
(18)bind
SOcketをアドレスにバインドします.
(19)accept
接続を受け入れ、socketと傍受アドレスにバインドする必要があります.
(20)close
ソケットを閉じます.
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クライアントの実装.

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
\r
' % 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  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()