Foundations of Python Network Programming

(WallPaper) #1

Chapter 7 ■ Server arChiteCture


132


Listing 7-9. Using the Old asyncore Framework


#!/usr/bin/env python3


Foundations of Python Network Programming, Third Edition


https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter07/srv_legacy2.py


Uses the legacy "asyncore" Standard Library module to write a server.


import asyncore, asynchat, zen_utils


class ZenRequestHandler(asynchat.async_chat):


def init(self, sock):
asynchat.async_chat.init(self, sock)
self.set_terminator(b'?')
self.data = b''


def collect_incoming_data(self, more_data):
self.data += more_data


def found_terminator(self):
answer = zen_utils.get_answer(self.data + b'?')
self.push(answer)
self.initiate_send()
self.data = b''


class ZenServer(asyncore.dispatcher):


def handle_accept(self):
sock, address = self.accept()
ZenRequestHandler(sock)


if name == 'main':
address = zen_utils.parse_command_line('legacy "asyncore" server')
listener = zen_utils.create_srv_socket(address)
server = ZenServer(listener)
server.accepting = True # we already called listen()
asyncore.loop()


This listing will raise red flags if you are an experienced Python programmer. The ZenServer object is never
handed to the asyncore.loop() method or explicitly registered in any way, yet the control loop seems magically
to know that the service is available! Clearly this module is trafficking in module-level globals or some other
nefariousness to build links between the main control loop, the server object, and the request handlers that it creates
but is doing so in a way you cannot quite see.
However, you can see that many of the same steps are accomplished under the hood, which asyncio had put
out in the open. New client connections each result in the creation of a new instance of ZenRequestHandler in whose
instance variables you can store any kind of state necessary to keep up with how the client conversation is going.
Furthermore, as is normal with these asynchronous frameworks that you have been examining, there is an asymmetry
between receiving and sending. Receiving data involves returning and handing control back to the framework
and then getting called back for each block of new bytes that arrives as input. But sending data is a fire-and-forget
operation—you hand the whole outgoing payload to the framework and can return control, confident that the
framework will make as many send() calls as necessary to get the data transmitted.

Free download pdf