我无法在 HTTP2 实现中更新流量控制 window,因此客户端无法发送其余数据

I am unable to update Flow control window in HTTP2 implementation, so the client is unable to send the rest of the data

我正在 Python 3.6 中实现简单的 asyncio HTTP2 服务器和客户端。 它需要实现流量控制。我在客户端使用函数 self.outbound_flow_control_window=2048 将流量控制 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,即使在接收到 window更新帧数

你有没有流量控制的示例服务器吗?如果不这样做。

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

This automatic strategy is built around a single method: acknowledge_received_data. This method flags to the connection object that your application has dealt with a certain number of flow controlled bytes, and that the window should be incremented in some way. Whenever your application has “processed” some received bytes, this method should be called to signal that they have been processed.

The key difference between this method and increment_flow_control_window is that the method acknowledge_received_data does not guarantee that it will emit a WINDOW_UPDATE frame, and if it does it will not necessarily emit them for only the stream or only the frame. Instead, the WINDOW_UPDATE frames will be coalesced: they will be emitted only when a certain number of bytes have been freed up.

现在看一下使用流控制的 curio 示例。如果您从服务器接收到 window 更新事件,您可能没有正确处理流 ID 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())

如果您想发送 4k 字节,请等待流量控制 window,发送您的 2k 字节,然后再次等待流量控制 window。

如果您收到 window 更新,您应该有这样的代码

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