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
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.
(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
def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
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()
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 '%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()