首页 > 解决方案 > libuv下读取数据时如何限制带宽

问题描述

众所周知,libuv 是一个异步网络库。
现在我用 libuv 编写了一个 http 下载客户端,但我不知道如何限制下载过程中的速度。也就是说,在libuv或异步网络库下读取数据时如何控制IO带宽?

类似问题:
1 、libuv下如何控制传输速度?
2. libuv #738中的限速方案

标签: limitbandwidthlibuv

解决方案


我最近实现了一个限制代理,我是这样做的:

在此示例中,我将假设最大带宽为 100kbps,超时时间为 10ms,并将错误处理留给您。

  • 呼叫read_start您的传入流
  • 在回调中立即调用read_stop
  • 根据您的最大 bps 和超时 (0.01s * maxBps = 1kB) 计算块大小
  • 将分块数据存储在某种集合中
  • 用我们的 10 毫秒超时启动一个计时器
  • 在您的计时器回调中:
    • 检查是否有剩余的块
    • 将一大块数据写入输出流
    • 如果还有更多块剩余,则重新启动计时器
    • 否则read_start再次调用您的输入流
  • 重复。

我在 Lua 中使用 luvit 进行了此操作,luvit 是 libuv 的包装器(+ 更多),但您应该能够轻松翻译有趣的部分。

这是 Lua 代码的相关部分以供参考。请注意,我在这里的写回调中启动了我的计时器,但这不应该有太大的不同。send_data_to_upstream是传入的流读取回调。


local send_next_chunk
local send_data_to_upstream

send_data_to_upstream = function(err, data)
    if err then debug_print("Client error:" .. err) end
    if data then
        -- throttle reads
        self.sock.tcp_client:read_stop()

        -- chunkify the data
        self.chunks = splitByChunk(data, self:_get_chunk_size())
        debug_print("[DOWN]", "Client request: " .. #data)
        send_next_chunk()
    else
        -- Client disconnected, cleanup handles
        self:disconnect()
        debug_print("Client disconnected")
    end
end

send_next_chunk = function()
    if #self.chunks > 0 then
        debug_print("[DOWN]", "Chunks remaining: ", #self.chunks,
                    "next in:", self.throttle.delay)
        timer.setTimeout(self.throttle.delay, function()
            -- throttle transfer for consecutive chunks
            self.throttle.delay = self.throttle.timeout_ms

            -- send next chunk
            local head = table.remove(self.chunks, 1)
            self.sock.tcp_upstream:write(head, send_next_chunk)
            collectgarbage("step")
        end)
    else
        -- restart the client data pump
        self.throttle.delay = 0
        debug_print("[DOWN]", "Client request completed")
        self.sock.tcp_client:read_start(send_data_to_upstream)
    end
end


推荐阅读