Правильный способ запуска сервера Trio, который управляет несколькими соединениями TCP - PullRequest
0 голосов
/ 05 мая 2019

Я недавно закончил проект, использующий смесь Django и Twisted, и понял, что это излишне для того, что мне нужно, и это просто способ для моих серверов общаться через TCP-сокеты. Я повернулся к Трио, и мне нравится то, что я вижу, так как оно более прямое (для того, что мне нужно). Тем не менее, я просто хотел быть уверен, что делаю это правильно.

Я следовал учебнику , который преподавал основы, но мне нужен сервер, который мог бы обрабатывать несколько клиентов одновременно. С этой целью я придумал следующий код

import trio
from itertools import count

PORT = 12345
BUFSIZE = 16384
CONNECTION_COUNTER = count()


class ServerProtocol:

    def __init__(self, server_stream):
        self.ident = next(CONNECTION_COUNTER)
        self.stream = server_stream

    async def listen(self):
        while True:
            data = await self.stream.receive_some(BUFSIZE)
            if data:
                print('{} Received\t {}'.format(self.ident, data))
                # Process data here


class Server:

    def __init__(self):
        self.protocols = []

    async def receive_connection(self, server_stream):
        sp: ServerProtocol = ServerProtocol(server_stream)
        self.protocols.append(sp)
        await sp.listen()


async def main():
    await trio.serve_tcp(Server().receive_connection, PORT)

trio.run(main)

Моя проблема здесь заключается в том, что каждый ServerProtocol запускает listen в каждом цикле, а не ожидает получения данных, которые будут получены.

У меня такое ощущение, что я использую Трио неправильно, и в этом случае я пропускаю лучшие практики Трио?

1 Ответ

0 голосов
/ 09 мая 2019

Ваша общая структура выглядит хорошо для меня.Проблема, которая возникает у меня:

    while True:
        data = await self.stream.receive_some(BUFSIZE)
        if data:
            print('{} Received\t {}'.format(self.ident, data))
            # Process data here

Гарантия, которую дает receive_some, заключается в следующем: если другая сторона уже закрыла соединение, то она немедленно возвращает пустую строку байтов.В противном случае он ожидает, пока не вернутся какие-то данные, а затем возвращает их в виде непустой строки байтов.

Таким образом, ваш код должен работать нормально ... пока другой конец не закроет соединение.Затем он начинает выполнять бесконечный цикл, где он продолжает проверять данные, возвращая пустую строку байтов (data = b""), так что блок if data: ... не запускается, и он немедленно возвращается к циклу, чтобы сделать это снова.

Один из способов это исправить (последние 3 строки новые):

    while True:
        data = await self.stream.receive_some(BUFSIZE)
        if data:
            print('{} Received\t {}'.format(self.ident, data))
            # Process data here
        else:
            # Other side has gone away
            break
...