Explore the newly introduced asyncio module in Python3.4

  • 2020-05-07 19:56:53
  • OfStack

USES Simple Protocol

The asyncio.BaseProtocol class is a common base class for the protocol interface (protocol interface) in the asyncio module. asyncio.Protocolclass inherits from asyncio.BaseProtocol and provides an interface for stream protocols. The following code demonstrates a simple implementation of the asyncio.Protocol interface, which behaves 1 like an echo server, and outputs 1 in the Python console. SimpleEchoProtocol inherits from asyncio.Protocol and implements three methods: connection_made, data_received and andconnection_lost:


import asyncio
 
class SimpleEchoProtocol(asyncio.Protocol):
  def connection_made(self, transport):
    """
    Called when a connection is made.
    The argument is the transport representing the pipe connection.
    To receive data, wait for data_received() calls.
    When the connection is closed, connection_lost() is called.
    """
    print("Connection received!")
    self.transport = transport
 
  def data_received(self, data):
    """
    Called when some data is received.
    The argument is a bytes object.
    """
    print(data)
    self.transport.write(b'echo:')
    self.transport.write(data)
 
  def connection_lost(self, exc):
    """
    Called when the connection is lost or closed.
    The argument is an exception object or None (the latter
    meaning a regular EOF is received or the connection was
    aborted or closed).
    """
    print("Connection lost! Closing server...")
    server.close()
 
loop = asyncio.get_event_loop()
server = loop.run_until_complete(loop.create_server(SimpleEchoProtocol, 'localhost', 2222))
loop.run_until_complete(server.wait_closed())

You can test echo server by running an telnet client program and connecting to port 2222 of localhost. If you are using this port, you can change the port number to any other port available. If you use the default values, you can run the above code in the Python console and then telnet localhost 2222 at a command prompt or terminal. You will see Connection received! Is displayed in the console of Python. Next, any character you enter in telnet's console will be displayed as echo: following the character you entered, and the character you just entered will be displayed in Python's console. When you exit the telnet console, you will see Connection lost! Closing server... Is displayed in the console of Python.

For example, if you type abc after opening telnet, you will see the following message in telnet's window:


 echo:abecho:bcecho:c

In addition, the following message is displayed in Python's console:


 Connection received!
 b'a'
 b'b'
 b'c'
 Connection lost! Closing server...

After creating an event loop named loop, the code calls loop.run_until_complete to run loop.create_server. This procedure creates an TCP server and USES protocol's factory class to bind to the specified port of the specified host (in this case port 2222 on localhost, SimpleEchoProtocol being used for the factory class) and returns an Server object to be used to stop the service. The code assigns this instance to the server variable. In this way, when a client connection is established, a new instance of SimpleEchoProtocol is created and the methods in the class are executed.

When a connection is successfully created, the code in the connection_made method outputs a message and assigns the received content as a parameter to the transport member variable for later use in another method.

When the incoming data is received, the code in the data_received aspect prints out the bytes of data received and sends echo: and received data to the client by calling the self.transport.write method twice. Of course, you could just call es95.transport.write once to return all the data, but I'd like to make a clear distinction between the code that sends echo: and the code that sends the received data.

When the connection is closed or disconnected, the code in the connection_lost method outputs a message and calls server.close (); At this point, the loop on line 1 stops running before the server shuts down.
USES Clients and Servers

In the above example, telnet is a client. The asyncio module provides a coroutine that makes it easy for you to write servers and clients using stream reader and writer. The following code demonstrates a simple echo server that listens on port 2222 on localhost. You can run the following code in Python's console, and then run the client code in another Python console as the client.


import asyncio
 
@asyncio.coroutine
def simple_echo_server():
  # Start a socket server, call back for each client connected.
  # The client_connected_handler coroutine will be automatically converted to a Task
  yield from asyncio.start_server(client_connected_handler, 'localhost', 2222)
 
@asyncio.coroutine
def client_connected_handler(client_reader, client_writer):
  # Runs for each client connected
  # client_reader is a StreamReader object
  # client_writer is a StreamWriter object
  print("Connection received!")
  while True:
    data = yield from client_reader.read(8192)
    if not data:
      break
    print(data)
    client_writer.write(data)
 
loop = asyncio.get_event_loop()
loop.run_until_complete(simple_echo_server())
try:
  loop.run_forever()
finally:
  loop.close()

The following code demonstrates a client program that connects to port 2222 on localhost, writes a few lines of data using the asyncio.StreamWriter object, and then reads the data returned by the server using the asyncio.StreamWriter object.
 


import asyncio
 
LASTLINE = b'Last line.\n'
 
@asyncio.coroutine
 def simple_echo_client():
  # Open a connection and write a few lines by using the StreamWriter object
  reader, writer = yield from asyncio.open_connection('localhost', 2222)
  # reader is a StreamReader object
  # writer is a StreamWriter object
  writer.write(b'First line.\n')
  writer.write(b'Second line.\n')
  writer.write(b'Third line.\n')
  writer.write(LASTLINE)
 
  # Now, read a few lines by using the StreamReader object
  print("Lines received")
  while True:
    line = yield from reader.readline()
    print(line)
    if line == LASTLINE or not line:
      break
  writer.close()
 
loop = asyncio.get_event_loop()
loop.run_until_complete(simple_echo_client())

You can execute client code in different Python consoles. If the server is running, the console outputs the following:


Lines received
b'First line.\n'
b'Second line.\n'
b'Third line.\n'
b'Last line.\n'

The Python console that executes the server-side code displays the following:


 Connection received!
 b'First line.\nSecond line.\nThird line.\nLast line.\n'

First, let's focus on the server-side code. After creating an event loop called loop, the code calls loop.run_until_complete to run the simple_echo_server coroutine. This coroutine calls asyncio.start_server to start one socket server, bind to the specified host and port number, and then, for each client connection, execute the incoming callback function as a parameter -- client_connected_handler. In this example, client_connected_handler is another coroutine and is not automatically converted to 1 Task. In addition to the coroutine (coroutine), you can specify a normal callback function.


Related articles: