Я не могу обновить окно управления потоком в реализации HTTP2, поэтому клиент не может отправить остальные данные - PullRequest
0 голосов
/ 10 февраля 2019

Я реализую простой 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 Ответ

0 голосов
/ 10 февраля 2019

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

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

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

https://python -hyper.org / projects / h2 / en / stable / advanced-Использование.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
...