limit - libuv下读取数据时如何限制带宽
问题描述
众所周知,libuv 是一个异步网络库。
现在我用 libuv 编写了一个 http 下载客户端,但我不知道如何限制下载过程中的速度。也就是说,在libuv或异步网络库下读取数据时如何控制IO带宽?
类似问题:
1 、libuv下如何控制传输速度?
2. libuv #738中的限速方案
解决方案
我最近实现了一个限制代理,我是这样做的:
在此示例中,我将假设最大带宽为 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
推荐阅读
- python - 错误:未找到雪花连接器-python==2.5.0 的匹配分布
- reactjs - 想要在“react-native-image-layout”中的图像模式上显示一个菜单栏,以提供删除等图像的选项
- c++ - 如何在 C++ 中记录屏幕时间?
- javascript - 更新 Mongoose 检索对象中的现有嵌套属性
- java - 取消刷新尝试:org.springframework.beans.factory.BeanDefinitionStoreException:无法解析配置类
- android - 您如何让订阅者订阅 kotlin sharedflow 并行运行操作?
- linux - 如何将 Linux 驱动程序与硬件设备匹配
- asp.net - ASP.NET 复选框在首次加载时不会触发检查更改事件
- vue.js - 在 Vue 3 中为 img src 使用具有动态名称的本地文件
- firebase - Streambuilder 不使用具有多个 where 子句的 Firebase 查询