How to pass additional parameters to handle_client coroutine?

∥☆過路亽.° 提交于 2019-12-31 01:46:07

问题


The recommended way to use asyncio for a socket server is:

import asyncio

async def handle_client(reader, writer):
    request = (await reader.read(100)).decode()
    response = "Data received." 
    writer.write(response.encode())

async def main():
    loop.create_task(asyncio.start_server(handle_client, 'localhost', 15555))

loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()

This works fine, but now I need to receive appropriate client request and then use aiohttp library to fetch data from a 3rd party restful API.

This requires creating a session variable as follows:

from aiohttp import ClientSession

session = ClientSession()

But this also should be inside a coroutine itself, so I'll put it inside main:

async def main():
    session = ClientSession()
    loop.create_task(asyncio.start_server(handle_client, '', 55555))

Now I need to pass the session variable to the aiohttp get coroutine to fetch the rest API data:

async with session.get(url, params=params) as r:
    try:
        return await r.json(content_type='application/json')
    except aiohttp.client_exceptions.ClientResponseError:
        ....

My question is how can I pass the session variable to handle_client coroutine, if it insists on only having reader,writer parameters, and globals don't help me because sessions must exist inside coroutines?


回答1:


You can use a temporary function or a lambda:

async def main():
    session = aiohttp.ClientSession()
    await asyncio.start_server(lambda r, w: handle_client(r, w, session),
                               '', 55555)

This works because even though the lambda is not technically a coroutine, it behaves like one - it is a callable that returns a coroutine object when invoked.

For larger programs you might prefer a class-based approach with a class encapsulating the state shared by multiple clients without having to pass it from coroutine to coroutine. For example:

class ClientContext:
    def __init__(self, session):
        self.session = session

    async def handle_client(self, reader, writer):
        # ... here you get reader and writer, but also have
        # session etc as self.session ...

async def main():
    ctx = ClientContext(aiohttp.ClientSession())
    await asyncio.start_server(ctx.handle_client), '', 55555)


来源:https://stackoverflow.com/questions/50678184/how-to-pass-additional-parameters-to-handle-client-coroutine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!