使用Boost Asio的快速数据(图像)传输服务器客户端

时间:2011-07-25 10:59:00

标签: c++ streaming client-server boost-asio

我对网络编程比较陌生,对使用Boost Asio在客户端和服务器之间进行连续快速数据(图像)传输的最佳实践有一些疑问。重要的是,我们不能应用降低图像质量的压缩。我们使用专用网络(54MBit),除了我们的网络之外没有其他流量。我们被推荐使用Boost Asio,因为它似乎适合我们的需求。然而,由于Boost功能强大,对于像我这样缺乏经验的(Boost)开发人员来说这是一项挑战。

我们希望开发一种尽可能简单的工具,在客户端和服务器之间尽可能快地连续发送图像数据。基本上它是流媒体。我们更愿意使用TCP,但如果我们可以通过UDP获得显着的性能提升,我们不会介意偶尔丢失数据包。

数据是无符号字符缓冲区(640x480px = 307200字节= 2.34MBit,单色)。

我从Asio教程开始,使用同步,异步,UDP,TCP项目。现在,我能够以~10fps发送数据,每个图像使用TCP约0.1ms,使用UDP约13fps。这太慢了。我希望在54MBit网络中发送2.4MBit更快。

今天,我不使用我的数据的序列化,存档和压缩(zip)等。我认为这会改善转移,但我想知道我是否必须满足我的期望和/或我是否必须完全改变我的方法?

将数据序列化作为与Asio进行数据流传输的方式吗? zip压缩可能会显着改善转移吗? 是否有替代方法或框架?

TCP服务器代码示例

// sends data whenever it receives a request by the client
int main(int argc, char* argv[])
{
init_image_buffer();
try
{
    boost::asio::io_service io_service;

    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));

    for (;;)
    {
        tcp::socket socket(io_service);
        acceptor.accept(socket);

        boost::system::error_code ignored_error;
        boost::asio::write(socket, boost::asio::buffer(image_buffer),
            boost::asio::transfer_all(), ignored_error);
    }
}
catch (std::exception& e)
{
    std::cerr << e.what() << std::endl;
}

return 0;
}

TCP客户端代码示例

我意识到这段代码不是最优的。但我无法弄清楚如何通过这种方法保持连接并请求新数据。

int main(int argc, char* argv[])
{
Clock clock;
clock.Initialise();

float avg = 0.0;
float min = 1000000.0;
float max = 0.0;
float time = 0.0;

// sending multiple images
for(int j=0;j<IMAGE_COUNT;j++){

    try
    {
        clock.GetTime();
        if (argc != 2)
        {
            std::cerr << "Usage: client <host>" << std::endl;
            return 1;
        }

        boost::asio::io_service io_service;

        tcp::resolver resolver(io_service);
        tcp::resolver::query query(argv[1], 13);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
        tcp::resolver::iterator end;

        tcp::socket socket(io_service);
        boost::system::error_code error = boost::asio::error::host_not_found;

        while (error && endpoint_iterator != end)
        {
            socket.close();
            socket.connect(*endpoint_iterator++, error);
        }
        if (error)
            throw boost::system::system_error(error);

        // we read all received data but do NOT save them into a dedicated image buffer
        for (;;)
        {
            boost::array<unsigned char, 65536> temp_buffer;
            boost::system::error_code error;

            size_t len = socket.read_some(boost::asio::buffer(temp_buffer), error);

            if (error == boost::asio::error::eof)
                break; // Connection closed cleanly by peer.
            else if (error)
                throw boost::system::system_error(error); // Some other error.

        }

        time = clock.GetTime();
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    // calculate some time transfer statistics
    avg+=time;
    if(time < min) min = time;
    if(time > max) max = time;

}
std::cout << "avg: " << avg/(float)IMAGE_COUNT << " freq: " << 1.0/(avg/(float)IMAGE_COUNT) << std::endl;
std::cout << "min: " << min << " max: " << max << std::endl;

return 0;
 }

5 个答案:

答案 0 :(得分:2)

您似乎正在将帧大小(2.34MBit)与网络速度(54MBit / sec)进行比较。如果是这种情况,并且你得到10 fps,你的实际速率是23.4 MBit / sec - 这在54 MBit / sec连接上也不错。

无论如何,请告诉我们您最终的设计。

感谢。

答案 1 :(得分:1)

如果考虑带宽并且你有足够的CPU,请看x264,它有一个无损压缩方案,可以很好地快速压缩。如果CPU更受限制,请查看libz甚至是简单的PNG库。 Imho具有良好的高级库,这些实现起来并不困难,通常只需要几个函数调用就可以获得数据。

至于数据可靠性。 TCP是一个简单的选择,但由于不可预测的延迟,抖动和快速重启,通常不鼓励实时流式传输,当涉及无线链路时(54mbps实际上让我想起)当然可以避免。 SCTP可能是更适合的替代方案,但还有更多(例如MPEG-TS,RSTP,......)。最后,您始终可以构建自己的协议,以便根据UDP重新传输错过/错误的帧,但这不是一项简单的任务。

编辑:您可以随时查看VNC / NX实施,如果图像没有快速变化,这些也可以帮助您。

答案 2 :(得分:0)

不是一个真正具体的答案,而是一些提示:

使用TCP。对于数据传输,速度要快得多,因为所有包的检查和重新发送都是内置且超快的。哎呀,发明了数据传输。如果您需要像在FPS游戏中那样实时发送大量单个包,请仅使用UDP。

使用快速无损压缩算法,例如FastLZ(我刚刚使用Google发现它,我没有经验)。它不会像纯粹的有损图像压缩算法一样工作,因为它知道它正在处理图像,但它可以处理任何类型的数据并对其进行压缩。

答案 3 :(得分:0)

根据您传输的数据,您可能会考虑仅发送图像与下一个图像之间的更改。这可能对远程桌面有用,但对视频无用。您可以通过更准确地告诉您要发送的数据类型来提供帮助。

答案 4 :(得分:0)

  • 实际上,您似乎拥有54Mbps的无线连接能力。如果是,您还有另一个问题,即此连接是半双工。因此,在这种情况下,请考虑您的网络带宽为27Mbps。
  • 此外,在无线网络中,延迟会增加,从而降低TCP性能。
  • 您可以尝试使用OpenCV库进行快速图像压缩。它们都提供有损和无损压缩选项(JPEG,PNG等)。
  • 如果您的流媒体图片变化不是太快,您可以尝试仅发送更改。您可以使用VLC库和OpenCV库来查找此更改数据。