Alan Alan - 2 months ago 19
Python Question

What are the requirements of a protocol factory in python asyncio?

I am looking at the example of the UDP echo server:

import asyncio

class EchoServerProtocol:
def connection_made(self, transport):
self.transport = transport

def datagram_received(self, data, addr):
message = data.decode()
print('Received %r from %s' % (message, addr))
print('Send %r to %s' % (message, addr))
self.transport.sendto(data, addr)

loop = asyncio.get_event_loop()
print("Starting UDP server")
# One protocol instance will be created to serve all client requests
listen = loop.create_datagram_endpoint(
EchoServerProtocol, local_addr=('127.0.0.1', 9999))
transport, protocol = loop.run_until_complete(listen)

try:
loop.run_forever()
except KeyboardInterrupt:
pass

transport.close()
loop.close()


It seems that the call...

loop.create_datagram_endpoint(EchoServerProtocol, local_addr=('127.0.0.1', 9999))


...is doing all the work here. The method documentation states the following for the first argument (
protocol_factory
):


protocol_factory must be a callable returning a protocol instance.


My questions:


  • What defines a
    protocol instance
    ?

  • Is
    returning a protocol instance
    a different wording for
    initiating a protocol object
    ?

  • How does the
    EchoServerProtocol
    in the example fulfill this requirement?


Answer

What defines a protocol instance?

A protocol is a class you define that implements one of the interfaces defined in the Protocols section, i.e. provides implementations for a set of callbacks, e.g. Connection Callbacks.

So for the UDP echo server example you have posted, the EchoServerProtocol user defined class actually defines a protocol by implementing the connection_made and datagram_received.

In summary, if you implement one of those callbacks in a class, you are said to be defining a Protocol. So an instance/object of that class would be a protocol instance.


Is returning a protocol instance a different wording for initiating a protocol object?

Formally YES. Before you would return a protocol instance, you would have initialized it. So basically one is a prerequisite of the other.


How does the EchoServerProtocol in the example fulfill this requirement?

So first of all, as answered the first question, the EchoServerProtocol defines a protocol. Thus the next thing is to provide a protocol_factory, which is defined as:

protocol_factory must be a callable returning a protocol instance.

So to satisfy this requirement, you could just have this simple method:

def my_protocol_factory():
    return EchoServerProtocol()

Note, that this factory first initializes the protocol instance and then returns it.

So the thing that might confuse you in the example, is that the class EchoServerProtocol itself is passed as the protocol_factory, but if you summarize what I've said, you will see that the EchoServerProtocol is actually a callable, and when it gets called, i.e. EchoServerProtocol() it actually initializes a EchoServerProtocol instance, and returns it.

So yep, the example fulfills the requirement.