ホームページ  >  記事  >  バックエンド開発  >  Python での asynccore 非同期モジュールの使用と httpclient の実装

Python での asynccore 非同期モジュールの使用と httpclient の実装

高洛峰
高洛峰オリジナル
2017-03-01 14:20:012068ブラウズ

asyncore は非同期ソケット パッケージであり、特にディスパッチャー クラスには非同期呼び出し用のソケット操作メソッドが多数含まれており、Python での asyncore 非同期モジュールの使用法と

基本
を説明しましょう。
このモジュールはソケットの非同期実装です。まず、モジュール内のいくつかのクラスとメソッドについて理解しましょう:
1.asyncore.loop

パス カウントまたは開いたチャネルが閉じるまで、ポーリング ループに入ります。

2.asyncore.dispatcher

ディスパッチャクラスは、基礎となるソケットクラスのラッパーオブジェクトです。より便利にするために、ループ内で非同期に呼び出されるイベント処理メソッドがいくつかあります。それ以外の場合は、標準の非ブロッキング ソケット オブジェクトです。
低レベル イベントは、特定の高レベル イベントが特定のイベントまたは特定の接続状態で発生したことを非同期ループに伝えます。たとえば、別のホストに接続するにはソケットが必要です。

(1) handle_connect() の最初の読み取りまたは書き込みイベント。
(2) handle_close() 読み取りイベントに使用できるデータがありません。
(3) handle_accept 読み取りイベントはソケットをリッスンします。
(4) handle_read

は、チャネルが read() を呼び出していることを非同期ループが検出したときに呼び出されます。

(5) handle_write

は、書き込み可能なソケットに書き込むことができることを非同期ループが検出したときに呼び出されます。多くの場合、このアプローチによりバッファリングのパフォーマンスが実現されます。例:

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

チャネルソケットを読み取りイベントリストに追加するかどうかを決定するために非同期ループ内で毎回呼び出されます。デフォルトは True です。

(12) writable

チャネルソケットを書き込みイベントリストに追加するかどうかを決定するために非同期ループ内で毎回呼び出されます。デフォルトは True です。

(13) create_socket

は標準ソケットを作成する場合と同じです。

(14) connect

は、標準ソケットのポート設定と同じで、最初のパラメータがホストアドレス、2 番目のパラメータがポート番号であるタプルを受け入れます。

(15) send

データをリモートソケットに送信します。

(16)recv

リモートソケットからbuffer_sizeまでのデータを読み込みます。空の文字列は、チャネルがもう一方の端から閉じられていることを意味します。

(17)listen

ソケット接続をリッスンします。

(18)bind

ソケットをアドレスにバインドします。

(19) accept

は接続を受け入れ、ソケットとリスニングアドレスにバインドする必要があります。

(20)close

ソケットを閉じます。

3.asyncore.dispatcher_with_send

ディスパッチャのサブクラスは、単純なクライアント用に単純なバッファ出力機能を追加し、より複雑なクライアントでは asynchat.async_chat を使用します。

4.asyncore.file_dispatcher

file_dispatcher は、survey() 関数またはloop() 関数を使用して、ファイル記述子またはファイルオブジェクトマップとオプションの引数ラッパーを受け取ります。ファイル オブジェクトまたは 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\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コア非同期モジュールのasyn httpclient の使用法と実装に関する記事は、PHP 中国語 Web サイトに注意してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。