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

标签 python-asyncio http2 flow-control hyper

我正在 Python 3.6 中实现简单的 asyncio HTTP2 服务器和客户端。 它需要实现流量控制。我在客户端使用函数 self.outbound_flow_control_window=2048 将流量控制窗口设置为 2048 字节,在客户端发送 2048 字节的数据 block 后,服务器不处理和确认接收到的数据,因此客户端可以发送另一 block 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,即使在接收到窗口更新帧之后也是如此

最佳答案

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

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 示例。如果您从服务器接收到窗口更新事件,您可能没有正确处理流 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 字节你在流量控制窗口等待,发送你的 2k 字节然后在流量控制窗口再次等待。

如果你正在接收窗口更新,你应该有这样的代码

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

关于python-asyncio - 我无法在 HTTP2 实现中更新流量控制窗口,因此客户端无法发送其余数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54616728/

相关文章:

python - 如何等待对象改变状态

node.js - Express http 2 服务器推送

http2 - 我可以通过 STDIN/STDOUT 说 HTTP/2 吗?

javascript - 如何使用 vo.js 在 for 循环中产生多个 Promise?

python - Python 中更容易的流控制

python-asyncio - 什么时候使用 loop.add_signal_handler?

python - 有没有办法直接在Jupyter cell中调用await?

python - 使用 @pytest.fixture(scope ="module") 和 @pytest.mark.asyncio

amazon-web-services - TCP 模式下基于 AWS ELB 的 HTTP2

java - java中用于流程控制的 boolean 逻辑运算符