How to access uvloop version of asyncio.Server from the StreamReader?

345 views Asked by At

Python 3.6 and 3.8.

I was using the following lines to start a server:

class MyServer:

    async def main(self, handler, host, port):
        self._server = await asyncio.start_server(handler, host=host, port=port)

        # Next line does not work with uvloop
        self._server._stop = False

where the _stop attribute would be added to access in the handler.

Then in the handler I would set the _stop attribute like so:

async def handler(reader, writer):
    writer._transport._server._stop = True

This works beautifully when not using uvloop. But when using uvloop, this no longer works.

When I try to set (!) the _stop attribute on the server object I immediately get this error:

AttributeError: 'uvloop.loop.Server' object has no attribute '_stop'

My question is how to "communicate" between the handler and the server ... ?

PS. When not using uvloop, this all works, because the StreamWriter._transport has an attribute _server.

1

There are 1 answers

3
Ytsen de Boer On

Thanks to @user4815162342, I could quite easily manage via simply passing a member function as call back.

This was not my first guess, because the member function takes three arguments, while the call back function takes two (search the web for "python bound method" for more on this and why the code below still works fine).

But the code below demonstrates how it works now:

import asyncio


class MyServerContext:

    async def handler(self, reader, writer):
        line = await reader.readline()
        if line == b'stop\n':
            setattr(self, '_stop', True)

    async def send_stop(self):

        _, writer = await asyncio.open_connection('localhost', 6369)
        writer.write(b'stop\n')
        await writer.drain()
        writer.close()
        await writer.wait_closed()

    async def start(self):

        server = await asyncio.start_server(
            self.handler,    # <---- Member function as call back
            'localhost',
            6369)

        while not getattr(self, '_stop', False):
            await self.send_stop()

        server.close()
        await server.wait_closed()


if __name__ == '__main__':
    server_context = MyServerContext()
    asyncio.get_event_loop().run_until_complete(server_context.start())
    exit(0)