c++:流媒体和速率调节
c++: streaming and rate regulation
我在一次采访中被问到一个有趣的问题:
假设您不断地从具有可变速率的源(假设为客户端-服务器模型)接收一些字节流。你想在你的一端对数据包进行动态排序,并以恒定的速率在其他地方重新传输。您将如何在C++中实现这样一个系统?
我提供了一个基本系统,其中有一个工作线程将数据包推到堆中,还有一个调度器线程弹出排序后的数据包,并以X的恒定间隔与一些内部时钟同步发送。
采访者合理地认为,由于线程之间的上下文切换,这样的系统很容易错过重新传输的最后期限。我回答说,如果没有对特定机器中的线程调度算法的任何控制,我就无法保证恒定的重传率。他坚持了下来,这让我觉得也许我错了,事实上这是可以实现的。那么,我是吗?
对问题的描述过于模糊。什么是"排序"?数据包的主体中有某种序列号吗?如果我们从来没有收到一些序列号的数据包呢?以下是我对一些可能适用于不同特定情况的通用算法的看法。
参数
算法取决于以下参数:
- 允许缓冲的最大数据包数(例如4096个)
- 水印值高。它是相对于(1)的百分比。如果我们当前在缓冲区中的数据包比HWV多,那么即使数据包没有按顺序排序,我们也会发送数据包。(50%或2048)
- TTL——我们允许缓冲数据包的最长时间
变量
首先,我们需要一个固定长度的环形缓冲区。环形缓冲区包括:
- 缓冲数据包的数组[4096]
- 进入上述数组的指针数组[4096](以避免在排序操作期间复制数据包本身)
- 每个数据包的元信息数组[4096]:其序列号(从数据包解析)和接收数据包的时间戳
- 指向头部和尾部
我们还需要存储全局变量——下一个要发送的序列号。
算法
当数据包到达时,我们将数据包添加到缓冲区的适当位置(插入排序的一步),所以我们的缓冲区总是按序列号排序。之后,如果以下至少一项为真,我们可能希望从缓冲区的头部发送数据包:
- 头数据包的序列号小于或等于预期的序列号。这意味着头数据包是按排序顺序排列的下一个。典型情况
- 缓冲区中的数据包数超过高水印值(2048)。我们发送头数据包(尽管它没有按顺序排列),因为我们担心传入活动的爆发可能会填满我们的缓冲区的其余部分,我们将不得不丢弃更多的传入数据包
- 当前时间减去头数据包到达时间超过TTL
如果上面至少有一个是真的,我们发送头数据包并将其从缓冲区中删除。我们还将预期的序列号指定为发送数据包的序列号加一。如果在发送头数据包后,缓冲区不为空,我们也会用TTL值重新启动计时器。当定时器启动时,我们执行与上述检查完全相同的检查。这是为了避免将数据包无限期地保留在缓冲区中(以防不再有传入的数据包)。
- 使用专用显卡进行 OpenGL 渲染时帧速率较低
- 在打开多个其他窗口时使用全屏窗口时帧速率非常低
- libcurl :显示正在运行的上传和下载速率
- 如何在IQualProp::get_AvgFrameRate中重置帧速率?
- 为什么当通过 TCP 发送的消息速率增加时,请求-响应消息对的延迟会降低?
- 同步两个具有不同帧速率的传感器
- 如何在不同的线程中保持一定的帧速率
- 根据帧速率缩放/缩小数字
- 将Kinect v2帧速率(rgb、深度、骨架)设置为每秒25帧
- 助推.野兽速率限制
- 直接显示返回错误的帧速率 FPS
- 在高数据包速率下最大限度地减少丢弃的 UDP 数据包 (Windows 10)
- SDL 帧速率上限实施
- 以高数据速率发送图像数据超过提升::asio::udp?
- 试图调节我的 do-while 以停止在终端中退出程序.菜单不会根据需要循环使用当前语句
- 我们应该认为评估特征检测,描述和匹配的主要速率和值是多少
- 在 OpenGL 中,在保持良好帧速率的同时,VBO 中有多少个顶点的好目标是什么
- 对"保存::速率"的未定义引用
- 如何调节类模板和原始类型模板
- c++:流媒体和速率调节