Home  >  Article  >  Backend Development  >  Usage of asyncore asynchronous module in Python and implementation of httpclient

Usage of asyncore asynchronous module in Python and implementation of httpclient

高洛峰
高洛峰Original
2017-03-01 14:20:012068browse

asyncore is an asynchronous socket package. In particular, the dispatcher class contains many socket operation methods for asynchronous calls, which is very sharp. Let's explain the usage of the asyncore asynchronous module in Python and the implementation of httpclient.

Basics
This module is an asynchronous implementation of socket. Let us first familiarize ourselves with some classes and methods in the module:
1.asyncore.loop

Enter a polling loop until the pass count or the open channel has been closed.

2.asyncore.dispatcher

The dispatcher class is a wrapper object of the underlying socket class. To make it more useful, it has some event handling methods that are called asynchronously in a loop. Otherwise it is a standard non-blocking socket object.
The low-level events tell the asynchronous loop that certain high-level events have occurred at specific events or specific connection states. For example, we ask a socket to connect to another host.

(1) handle_connect() first read or write event.
(2) handle_close() No data is available for the read event.
(3) handle_accept reads the event and monitors a socket.
(4)handle_read

Called when the asynchronous loop detects that the channel calls read().

(5) handle_write

is called when the asynchronous loop detects that a writable socket can be written. This approach often achieves buffering performance. For example,

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

(6) handle_expt

When there is an (OOB) data socket connection. This almost never happens, since OOB is poorly supported and rarely used.

(7)handle_connect

Called when the socket creates a connection.

(8)handle_close

Called when the socket connection is closed.

(9) handle_error

Called when an exception is raised and there is no other processing.

(10)handle_accept

Called when the local listening channel establishes a connection with the remote end (passive connection).

(11)readable

Called every time in the asynchronous loop to determine whether to add a channel socket to the read event list, the default is True.

(12)writable

Called every time in the asynchronous loop to determine whether to add a channel socket to the write event list, the default is True.

(13) create_socket

is the same as when creating a standard socket.

(14)connect

is the same as the port setting of standard socket. It accepts a tuple whose first parameter is the host address and the second parameter is the port number.

(15) send

Send data to the remote socket.

(16)recv

Read up to buffer_size data from the remote socket. An empty string means the channel is closed from the other end.

(17)listen

Listen to the socket connection.

(18)bind

Bind the socket to the address.

(19)accept

To accept a connection, it must be bound to a socket and listening address.

(20)close

Close the socket.

3.asyncore.dispatcher_with_send

The dispatcher subclass adds a simple buffered output function for simple clients, and more complex ones use asynchat.async_chat.

4.asyncore.file_dispatcher

file_dispatcher takes a file descriptor or file object map and an optional argument, wrapper, using survey() or loop() function. If a file object or any fileno() method is provided, that method will be called and passed to the file_wrapper constructor. Availability: UNIX.

5.asyncore.file_wrapper

file_wrapper takes an integer file descriptor and calls os.dup() to copy the handler, so that the original handler may be closed independently of file_wrapper . This class implements enough methods to simulate a socket using the file_dispatcher class. Availability: UNIX.

asyncore Example

1. Implementation of an 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()

Server accepts connections and assigns tasks

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. Use asyncore’s port mapping (port forwarding)

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

More articles related to the usage of asyncore asynchronous module in Python and the implementation of httpclient Please pay attention to PHP Chinese website!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn