Я не могу обновить окно управления потоком в реализации HTTP2, поэтому клиент не может отправить остальные данные

Я реализую простой сервер и клиент asyncio HTTP2 в Python 3.6. Требуется реализовать управление потоком. Я установил окно управления потоком на 2048 байт на стороне клиента с функцией self.outbound_flow_control_window=2048, после того как клиенты отправляют 2048-байтовый фрагмент данных, сервер не обрабатывает и не подтверждает полученные данные, поэтому клиент может отправить еще один фрагмент 2048 байтов

я уже пробовал эти функции, self.conn.acknowledge_received_data(2048, event.stream_id) self.conn.increment_flow_control_window(2048, event.stream_id)

elif isinstance(event, DataReceived):
    self.receive_data(event.data, event.stream_id)
    self.conn.acknowledge_received_data(2048, event.stream_id)
    self.conn.increment_flow_control_window(2048, event.stream_id)

После получения данных (2048 байт) от клиента я хочу, чтобы сервер подтвердил и обновил клиенту, что он может отправлять больше данных сейчас, но flow_control_windows на клиенте остается 0, даже после получения кадров обновления окна

1 ответ

Решение

У вас есть пример сервера без управления потоком? Если не так.

https://github.com/python-hyper/hyper-h2/blob/master/examples/asyncio/asyncio-server.py

Вы смешиваете ручное и автоматическое управление потоком. Перечитайте раздел автоматического управления потоком здесь и используйте автоматический контроль.

https://python-hyper.org/projects/h2/en/stable/advanced-usage.html

Эта автоматическая стратегия построена вокруг одного метода:cknowledge_received_data. Этот метод указывает объекту соединения, что ваше приложение имеет дело с определенным количеством байтов, контролируемых потоком, и что окно должно быть увеличено каким-то образом. Всякий раз, когда ваше приложение "обработало" некоторые полученные байты, этот метод следует вызывать, чтобы сообщить, что они были обработаны.

Основное различие между этим методом и increment_flow_control_window заключается в том, что метод acceptledge_received_data не гарантирует, что он будет излучать кадр WINDOW_UPDATE, и если он это сделает, он не обязательно будет излучать их только для потока или только для кадра. Вместо этого кадры WINDOW_UPDATE будут объединены: они будут излучаться только после освобождения определенного количества байтов.

Теперь посмотрим на пример curio, который использует управление потоком. Если вы получаете события обновления окна с сервера, скорее всего, вы неправильно обрабатываете идентификатор потока 0.

https://github.com/python-hyper/hyper-h2/blob/master/examples/curio/curio-server.py

В частности, функция отправки данных:

 while True:
        while not self.conn.local_flow_control_window(stream_id):
            await self.wait_for_flow_control(stream_id)

        chunk_size = min(
            self.conn.local_flow_control_window(stream_id),
            READ_CHUNK_SIZE,
        )

        data = fileobj.read(chunk_size)
        keep_reading = (len(data) == chunk_size)

        self.conn.send_data(stream_id, data, not keep_reading)
        await self.sock.sendall(self.conn.data_to_send())

Если вы хотите отправить 4 Кбайт, которые вы ждете в окне управления потоком, отправьте 2 Кбайт, а затем снова подождите в окне управления потоком.

Если вы получаете обновление окна, вы должны иметь такой код

async def window_updated(self, event):
    """
    Unblock streams waiting on flow control, if needed.
    """
    stream_id = event.stream_id

    if stream_id and stream_id in self.flow_control_events:
        evt = self.flow_control_events.pop(stream_id)
        await evt.set()
    elif not stream_id:
        # Need to keep a real list here to use only the events present at
        # this time.
        blocked_streams = list(self.flow_control_events.keys())
        for stream_id in blocked_streams:
            event = self.flow_control_events.pop(stream_id)
            await event.set()
    return
Другие вопросы по тегам