c++:流媒体和速率调节

c++: streaming and rate regulation

本文关键字:速率 调节 流媒体 c++      更新时间:2023-10-16

我在一次采访中被问到一个有趣的问题:

假设您不断地从具有可变速率的源(假设为客户端-服务器模型)接收一些字节流。你想在你的一端对数据包进行动态排序,并以恒定的速率在其他地方重新传输。您将如何在C++中实现这样一个系统?

我提供了一个基本系统,其中有一个工作线程将数据包推到堆中,还有一个调度器线程弹出排序后的数据包,并以X的恒定间隔与一些内部时钟同步发送。

采访者合理地认为,由于线程之间的上下文切换,这样的系统很容易错过重新传输的最后期限。我回答说,如果没有对特定机器中的线程调度算法的任何控制,我就无法保证恒定的重传率。他坚持了下来,这让我觉得也许我错了,事实上这是可以实现的。那么,我是吗?

对问题的描述过于模糊。什么是"排序"?数据包的主体中有某种序列号吗?如果我们从来没有收到一些序列号的数据包呢?以下是我对一些可能适用于不同特定情况的通用算法的看法。

参数

算法取决于以下参数:

  1. 允许缓冲的最大数据包数(例如4096个)
  2. 水印值高。它是相对于(1)的百分比。如果我们当前在缓冲区中的数据包比HWV多,那么即使数据包没有按顺序排序,我们也会发送数据包。(50%或2048)
  3. TTL——我们允许缓冲数据包的最长时间

变量

首先,我们需要一个固定长度的环形缓冲区。环形缓冲区包括:

  1. 缓冲数据包的数组[4096]
  2. 进入上述数组的指针数组[4096](以避免在排序操作期间复制数据包本身)
  3. 每个数据包的元信息数组[4096]:其序列号(从数据包解析)和接收数据包的时间戳
  4. 指向头部和尾部

我们还需要存储全局变量——下一个要发送的序列号。

算法

当数据包到达时,我们将数据包添加到缓冲区的适当位置(插入排序的一步),所以我们的缓冲区总是按序列号排序。之后,如果以下至少一项为真,我们可能希望从缓冲区的头部发送数据包:

  1. 头数据包的序列号小于或等于预期的序列号。这意味着头数据包是按排序顺序排列的下一个。典型情况
  2. 缓冲区中的数据包数超过高水印值(2048)。我们发送头数据包(尽管它没有按顺序排列),因为我们担心传入活动的爆发可能会填满我们的缓冲区的其余部分,我们将不得不丢弃更多的传入数据包
  3. 当前时间减去头数据包到达时间超过TTL

如果上面至少有一个是真的,我们发送头数据包并将其从缓冲区中删除。我们还将预期的序列号指定为发送数据包的序列号加一。如果在发送头数据包后,缓冲区不为空,我们也会用TTL值重新启动计时器。当定时器启动时,我们执行与上述检查完全相同的检查。这是为了避免将数据包无限期地保留在缓冲区中(以防不再有传入的数据包)。