Maison  >  Article  >  développement back-end  >  Utilisation du module asynchrone asyncore en Python et implémentation de httpclient

Utilisation du module asynchrone asyncore en Python et implémentation de httpclient

高洛峰
高洛峰original
2017-03-01 14:20:012085parcourir

asyncore est un package de socket asynchrone, en particulier la classe dispatcher contient de nombreuses méthodes d'opération de socket pour les appels asynchrones, ce qui est très précis. Expliquons l'utilisation du module asynchrone asyncore en Python et l'implémentation de l'exemple httpclient

Bases
Ce module est une implémentation asynchrone de socket. Commençons par nous familiariser avec quelques classes et méthodes du module :

1.asyncore.loop

Entrez dans une boucle d'interrogation jusqu'à ce qu'un décompte de passes ou qu'un canal ouvert soit fermé.

2.asyncore.dispatcher

La classe dispatcher est un objet wrapper de la classe socket sous-jacente. Pour le rendre plus utile, il dispose de méthodes de gestion d'événements qui sont appelées de manière asynchrone dans une boucle. Sinon, il s’agit d’un objet socket standard non bloquant.

Les événements de bas niveau indiquent à la boucle asynchrone que certains événements de haut niveau se sont produits lors d'événements spécifiques ou d'états de connexion spécifiques. Par exemple, nous demandons à un socket de se connecter à un autre hôte.

(1) handle_connect() premier événement de lecture ou d'écriture.

(2) L'événement de lecture handle_close() n'a aucune donnée disponible.
(3) l'événement handle_accept read écoute une socket.
(4) handle_read

est appelé lorsque la boucle asynchrone détecte que le canal appelle read().

(5) handle_write

est appelé lorsque la boucle asynchrone détecte qu'un socket inscriptible peut être écrit. Cette approche permet souvent d'obtenir des performances de mise en mémoire tampon. Par exemple,

def handle_write(self):
  sent = self.send(self.buffer)
  self.buffer = self.buffer[sent:]

(6) handle_expt

lorsqu'il y a une connexion de prise de données (OOB). Cela n'arrive presque jamais, car OOB est mal pris en charge et rarement utilisé.

(7) handle_connect

Appelé lorsque le socket crée une connexion.

(8) handle_close

Appelé lorsque la connexion socket est fermée.

(9) handle_error

Appelé lorsqu'une exception est levée et qu'il n'y a aucun autre traitement.

(10) handle_accept

Appelé lorsque le canal d'écoute local établit une connexion avec l'extrémité distante (connexion passive).

(11) readable

est appelé à chaque fois dans la boucle asynchrone pour déterminer s'il faut ajouter un socket de canal à la liste des événements de lecture. La valeur par défaut est True.

(12) writable

Appelé à chaque fois dans la boucle asynchrone pour déterminer s'il faut ajouter un socket de canal à la liste des événements d'écriture, la valeur par défaut est True.

(13) create_socket

est le même que lors de la création d'un socket standard.

(14) connect

est le même que le paramètre de port du socket standard. Il accepte un tuple dont le premier paramètre est l'adresse de l'hôte et le deuxième paramètre est le numéro de port.

(15) envoyer

Envoyer des données à la prise distante.

(16) recv

Lire les données jusqu'à buffer_size à partir du socket distant. Une chaîne vide signifie que le canal est fermé à l'autre extrémité.

(17) écouter

Écouter la connexion de la prise.

(18)bind

Lier le socket à l'adresse.

(19) accepter

Pour accepter une connexion, elle doit être liée à une socket et à une adresse d'écoute.

(20) fermer

Fermez la prise.

3.asyncore.dispatcher_with_send

La sous-classe du répartiteur ajoute une simple fonction de sortie tampon pour les clients simples, et les plus complexes utilisent asynchat.async_chat.

4.asyncore.file_dispatcher

file_dispatcher prend un descripteur de fichier ou une carte d'objet de fichier et un argument facultatif, wrapper, en utilisant la fonction Survey() ou Loop(). Si un objet fichier ou une méthode fileno() est fourni, cette méthode sera appelée et transmise au constructeur file_wrapper. Disponibilité : UNIX.

5.asyncore.file_wrapper

file_wrapper prend un descripteur de fichier entier et appelle os.dup() pour copier le gestionnaire, afin que le gestionnaire d'origine puisse être fermé indépendamment de file_wrapper . Cette classe implémente suffisamment de méthodes pour simuler un socket à l'aide de la classe file_dispatcher. Disponibilité : UNIX.

Instance asyncore

1. Implémentation d'un client 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()

Le serveur accepte les connexions et attribue des tâches

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. Utiliser le mappage de port d'asyncore (redirection de port)

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()

En savoir plus sur le module asynchrone asyncore en Python Pour les articles liés à l'utilisation et à la mise en œuvre de httpclient, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn