Python's Asyncore asynchronous socket module and example of implementing port forwarding

Source: Internet
Author: User
The Asyncore module provides an asynchronous way to write the infrastructure of the socket service client and server.

There are only two ways to enable a program to implement "doing more than one thing at the same time" on a single processor. Multithreaded programming is the simplest and most popular way, but there is another very different technology that allows us to maintain almost all the advantages of multithreading without actually using multithreading. If your program is mostly I/O-bound, this is the only possible way. If your program is processor-bound, the preemptive dispatch thread may be what you really need. However, few network servers are processor-bound.

If your operating system supports select () system calls in its I/O library (almost all systems support), then you can use it to process multiple communication channels at once, and handle other work when your I/O is busy in the background. While this strategy seems strange and complex, especially at the very beginning, it is easier to understand and control in many ways than multithreaded programming. The Asyncore module solves a lot of difficulties for you, enabling you to quickly build complex, high-performance network servers and clients. For session applications and protocols, the Asynchat module is very useful.

The idea behind the two modules is to create one or more network channels, and instances of the Asyncore.dispatcher and Asynchat.async_chat classes. If you do not provide your own mappings, the Create channel will add these two instances to the global mappings used by the loop () function.

Once the initialization channel is created, calling the loop () function activates the channel service, which continues until the last channel (including all the channels that are added to the map in the asynchronous service) is closed.
The module file contains a loop () function and a dispatcher base class, where the loop () function is a global function that checks for a dict that holds the dispatcher instance, also known as the channel.
Each object that inherits the dispatcher class can be seen as a socket that needs to be processed, so we just need to define a class that inherits dispatcher, and then rewrite some of the methods, usually starting with Handle_.

Example of Port forwarding
If your program wants to do one thing at a time, multithreading is the quickest and most common way, but there is also a way to be particularly useful when I/O traffic is large. If your operating system supports the Select function, you can let I/O read and write in the background. This module sounds complicated, but there are actually many ways to understand it, and this document helps you solve these problems.
I feel like this module should be an event-driven asynchronous I/O, similar to the C + + event selection model. Each time a read or write event occurs, it is processed by our overridden event function.
I have here a script that uses the Asyncore module to write port forwarding, from which the script can probably understand the basic use of asyncore.
In the article, the client is our computer, the server is forwarded to the address. That is, the message sent by the client to this script, which is forwarded to the server.
First, define a forwarder class:

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)

This class inherits from the dispatcher class of the Asyncore module (which is our main class, which includes some functions to be overloaded later), the constructor obtains 5 parameters, the 1th and 2 parameters are the local IP and port of the script listener, and the 3 and 4 parameters are the IP and port of the server. The 5th parameter is the parameter of the Listen function, which waits for the maximum length of the queue.
How to use this class, just create a new object as follows, pass the corresponding IP and port, and then into the loop:

Forwarder (Options.local_ip,options.local_port,options.remote_ip,options.remote_port) Asyncore.loop ()

Entering the loop is equivalent to opening a daemon thread, running in the background, waiting for the socket event to occur.
Because our script is a port forwarding tool, the actual process of running is: the client connects to the port of this script, so that the data script sent to this port is automatically forwarded to the server address and port. Therefore, the first thing to receive is the connection message (the Accept event).
Then, when the Accept event occurs, it enters the handle_accept function. So we see that the handle_accept function actually calls the Accept function to receive the client connection object and address. After the acquisition, a new sender class object is created, which is defined as follows:

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 '%sent    self.receiver.from_remote_buffer = Self.receiver.from_remote_buffer[sent:]  def handle_close (self):    self.close ()    self.receiver.close ()

This class is also inherited from the Asyncore.dispatcher, its constructor receives 3 parameters, namely the Recv object (later said), the remote address, the corresponding port.
A new socket is created in the function, which is the socket that communicates with the server port and then connects to this port by calling Connect.
After that, it was also a process of waiting for a message, because we sent a connect, so the next message we received should be connect, and Handle_connect was a pass-off function. No content was executed.
After the connection is complete, we are setting up a port forwarding channel. When the client sends a packet to the port that the script listens to, it is automatically forwarded to the server port. The packets returned by the server port are automatically forwarded to the client.
Back to the 1th parameter of the constructor, we can see in the Forwarder class function that the incoming receiver (conn) object, receiver is also a class, let's look at the definition of this class:

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

It also inherits the Asyncore.dispatcher, and the constructor takes only one parameter, which is the return value of Connect, a connection object.
In fact, this object is to listen to and handle the communication with the client, and the sender object is to listen, to handle the communication with the server.

The above is the Python asyncore asynchronous socket module and implementation of port forwarding examples of content, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.