Я не могу обновить окно управления потоком в реализации 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