Как передать дополнительные параметры сопрограмме handle_client? - PullRequest
0 голосов
/ 04 июня 2018

Рекомендованный способ использования asyncio для сервера сокетов:

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()

Это работает нормально, но теперь мне нужно получить соответствующий клиентский запрос, а затем использовать библиотеку aiohttp для получения данных от стороннего отдыха.API.

Для этого необходимо создать переменную сеанса следующим образом:

from aiohttp import ClientSession

session = ClientSession()

Но это также должно быть внутри самой сопрограммы, поэтому я помещу ее в main:

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

Теперь мне нужно передать переменную сеанса в сопрограмму get aiohttp для получения остальных данных API:

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

Мой вопрос: как передать переменную сеанса в сопрограмму handle_client, если она настаиваеттолько наличие чтения, параметров записи и глобальных переменных не помогает мне, потому что сеансы должны существовать внутри сопрограмм?

1 Ответ

0 голосов
/ 04 июня 2018

Вы можете использовать временную функцию или лямбду:

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

Это работает, потому что, хотя lambda технически не является сопрограммой, он ведет себя как единица - это вызываемый элемент, который возвращает объект сопрограммы при вызове.

Для более крупных программ вы можете предпочесть подход на основе классов с классом, инкапсулирующим состояние, совместно используемое несколькими клиентами, без необходимости передавать его из сопрограммы в сопрограмму.Например:

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)
...