设计一个 C++ asio 流服务器

Posted

技术标签:

【中文标题】设计一个 C++ asio 流服务器【英文标题】:Designing a C++ asio streaming server 【发布时间】:2016-03-18 15:39:30 【问题描述】:

我正在尝试使用 asio 库(非增强版本)在 C++ 中构建网络服务器。我需要从相机拍摄图像并通过网络传输它们。我以前玩过asio,但这是我第一次尝试做一些“有意义的”事情,所以我可能以错误的方式理解了一些事情。我不确定在 asio 通过网络发送帧的情况下如何最好地处理。

我有一个线程与摄像头后端通信,以尽可能快的速度获取帧(例如 60 FPS、120 FPS)。

asio配置为:

1 个 io_service 对象 每个 CPU 内核一个线程来处理 io_service::run()

场景 1:

帧被相机线程复制到三重缓冲区中 由“服务器”实体拥有。每次生成新帧时,相机线程都会通知服务器,并切换缓冲区以便 获取“最新帧”。服务器监听并接受多个客户端连接async_accept

对于每个连接,服务器都会发送新的帧缓冲区。每个连接都会发出一个 asio async_write。 服务器等待所有完成处理程序完成 在切换到新帧之前,因为缓冲区无法更改,而 asio 写操作正在进行中。 在这种情况下,不会重新触发 asio 操作 完成处理程序,asio 操作仅由服务器发出。

我在这种方法中看到的问题:

由于服务器等待传输到所有连接的客户端 它可能会丢失来自相机后端的帧 我有这个作为我当前的实现,但它不能很好地扩展 - 随着我不断添加更多客户端,吞吐量急剧下降 似乎是对 asio 功能的使用不佳

场景 2:

相机线程将帧复制到“服务器”实体拥有的缓冲区中。每个连接对象都有自己的三重缓冲区。 每次生成新帧时,相机线程都会通知服务器,并将缓冲区复制到属于连接的所有三重缓冲区。在复制期间锁定服务器缓冲区。 服务器监听并接受多个客户端连接async_accept

在流式传输开始时,每个连接都会切换其三重缓冲区以获取“最新帧”并发出 asio async_write。在这种情况下,每个连接都会重新触发完成处理程序中的 asio async_write 操作。

我在这种方法中看到的问题:

由于每个连接有一个三重缓冲区,内存使用量将显着增加 当服务器将缓冲区复制到所有客户端时,它需要锁定它以防丢失 来自源的帧 如果服务器更新三重缓冲区的速度不够快,更快的客户端可能会发送两次相同的帧

我想知道这些方法在 asio 的上下文中是否有意义,以及可以采取哪些不同的方式来改进设计。我不是在寻找明确的解决方案,而是在寻找正确的方向。

我仔细查看了 asio 示例代码,但找不到任何类似于我的示例。

【问题讨论】:

【参考方案1】:

首先我要说的是,这对于单个 SO 线程来说太大了。但是看了想法后的一些想法:

    网络带宽呢?

通过正确的缓冲,ASIO 可以管理 I/O 速率,但如果您想为多个客户端提供服务,带宽可能是最近的引导瓶颈。查看a calculator:即使是中等质量的 30fps,您也可以达到 28Mbps。在这种情况下,1Gb 网络只允许您为 36 个客户端提供服务。压缩可能会有所帮助,但这是 CPU 的权衡。

    内存消耗。

如果相机继续以 60FPS 的速度生成帧,您应该能够以这种速度将这些数据传送给客户端。如果客户端是另一台具有良好硬件和网络链接的服务器,它可能不会产生问题。但是,如果客户端连接不良或滞后怎么办?在这种情况下,带宽会下降,您的服务器应该推迟/减慢对网络的写入。使用无限的写缓冲区,这将吃掉所有的 RAM。现在,如果您有很多客户并且他们有不同的接收速度,则会出现更多问题。处理这个需要仔细检查缓冲/写入队列/丢帧机制。

    要求

我认为您的要求存在一些差距。最低要求60FPS吗?什么延迟?你有哪些客户?如果您不能以这种速度发送帧,您可以丢弃多少帧以节省内存?他们有什么硬件?你有硬件限制吗?我认为回答这些问题以及更多问题并进行计算非常重要,这样您才能更好地回答如何做到这一点。

【讨论】:

感谢您的回答。实际上,该职位的范围可能过于广泛。我会尝试将其拆分为多个问题...

以上是关于设计一个 C++ asio 流服务器的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ ASIO 库用 C# 录制音频流

C++ asio 提供线程的异步执行

使用 boost-asio 的 C++ 和 Python 程序之间的客户端服务器

c++ - Boost ASIO 网络服务器/客户端

C++ Boost Asio 简单聊天教程

C++ Boost asio 连接和流式传输