Chapter 7 ■ Server arChiteCture
129
The asyncio framework supports two programming styles. One, which reminds programmers of the old Twisted
framework under Python 2, lets the user keep up with each open client connection by means of an object instance. In
this design pattern, the steps that Listing 7-6 took to advance a client conversation become method calls on the object
instance. You can see the familiar steps of reading in a question and reeling off a response in Listing 7-7, written in a
way that plugs directly into the asyncio framework.
Listing 7-7. An asyncio Server in the Callback Style
#!/usr/bin/env python3
Foundations of Python Network Programming, Third Edition
https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter07/srv_asyncio1.py
Asynchronous I/O inside "asyncio" callback methods.
import asyncio, zen_utils
class ZenServer(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
self.address = transport.get_extra_info('peername')
self.data = b''
print('Accepted connection from {}'.format(self.address))
def data_received(self, data):
self.data += data
if self.data.endswith(b'?'):
answer = zen_utils.get_answer(self.data)
self.transport.write(answer)
self.data = b''
def connection_lost(self, exc):
if exc:
print('Client {} error: {}'.format(self.address, exc))
elif self.data:
print('Client {} sent {} but then closed'
.format(self.address, self.data))
else:
print('Client {} closed socket'.format(self.address))
if name == 'main':
address = zen_utils.parse_command_line('asyncio server using callbacks')
loop = asyncio.get_event_loop()
coro = loop.create_server(ZenServer, *address)
server = loop.run_until_complete(coro)
print('Listening at {}'.format(address))
try:
loop.run_forever()
finally:
server.close()
loop.close()