简体   繁体   English

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

[英]Fast data (image) transfer server client using Boost Asio

I'm relatively new to network programming and have some questions on best practices for continuous fast data (image) transfer between a client and a server using Boost Asio. 我对网络编程比较陌生,对使用Boost Asio在客户端和服务器之间进行连续快速数据(图像)传输的最佳实践有一些疑问。 Important point, we cannot apply compression that lowers image quality. 重要的是,我们不能应用降低图像质量的压缩。 We use a dedicated network (54MBit) with no traffic other than ours. 我们使用专用网络(54MBit),除了我们的网络之外没有其他流量。 We were recommended to use Boost Asio, since it seems to be suited for our needs. 我们被推荐使用Boost Asio,因为它似乎适合我们的需求。 However, as Boost is powerful it is challenging for inexperienced (Boost) developers like me. 然而,由于Boost功能强大,对像我这样缺乏经验的(Boost)开发人员来说是一项挑战。

We want to develop a tool, as simple as possible, that sends continuously image data as fast as possible between a client and a server. 我们希望开发一种尽可能简单的工具,在客户端和服务器之间尽可能快地连续发送图像数据。 Basically it is streaming. 基本上它是流媒体。 We would prefer to use TCP, but if we could have significant performance gain with UDP, we would not mind losing data packets once in a while. 我们更愿意使用TCP,但如果我们可以通过UDP获得显着的性能提升,我们不介意偶尔丢失数据包。

The data is an unsigned char buffer (640x480px = 307200 byte = 2.34MBit, monochrome). 数据是无符号字符缓冲区(640x480px = 307200字节= 2.34MBit,单色)。

I started with the Asio tutorials and played around with sync, async, UDP, TCP projects. 我从Asio教程开始,使用同步,异步,UDP,TCP项目。 For now I'm able to send data with ~10fps, ~0.1ms per image with TCP and ~13fps with UDP. 现在,我能够以~10fps发送数据,每个图像使用TCP约0.1ms,使用UDP约13fps。 This is far too slow. 这太慢了。 I expected sending 2.4MBit in a 54MBit network to be way faster. 我希望在54MBit网络中发送2.4MBit更快。

Today, I do not use serialization, archive and compression (zip) etc of my data. 今天,我不使用我的数据的序列化,存档和压缩(zip)等。 I think this will improve the transfer, but I'm wondering if I have to settle my expectations and/or if I have to change my approach entirely? 我认为这会改善转会,但我想知道我是否必须满足我的期望和/或我是否必须完全改变我的方法?

Is serialization of data the way to go for data streaming with Asio? 将数据序列化作为与Asio进行数据流传输的方式吗? Will zip compression improve the transfer probably significantly? zip压缩可能会显着改善转移吗? Are there alternative approaches or frameworks? 有替代方法或框架吗?

TCP Server code sample 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 Client code sample TCP客户端代码示例

I realize that this code is not optimal. 我意识到这段代码不是最优的。 But I couldn't figure out how to remain connected and requesting new data with this kind of approach. 但我无法弄清楚如何通过这种方法保持连接并请求新数据。

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;
 }

It seems you are comparing frame size (2.34MBit) with the network speed (54MBit/sec). 您似乎正在将帧大小(2.34MBit)与网络速度(54MBit / sec)进行比较。 If that's the case, and you are getting 10 fps, your actual rate is 23.4 MBit/sec –– which is not that bad on a 54 MBit/sec connection. 如果是这种情况,并且你得到10 fps,你的实际速率是23.4 MBit / sec - 这对于54 MBit / sec连接来说并不是那么糟糕。

Anyway, please inform us what design you ended up with. 无论如何,请告诉我们你最终的设计。

Thanks. 谢谢。

If bandwidth is a concern and you have enough CPU, look at x264 , it has a lossless scheme which compresses quite well and fast. 如果带宽是一个问题,你有足够的CPU,看看x264 ,它有一个无损压缩方案,可以很好地快速压缩。 If CPU is more limited, take a look at libz or even a simple PNG library. 如果CPU更受限制,请查看libz甚至是简单的PNG库。 Imho with good high level libraries these are not so difficult to implement, often it's just a few function calls and you have your data. Imho具有良好的高级库,这些实现起来并不困难,通常只需要几个函数调用就可以获得数据。

As for data reliability. 至于数据可靠性。 TCP is the easy choice but is often not encouraged for real time streaming because of unpredictable latencies, jitter and the fast-restart, certainly avoidable when a wireless link is involved (which the 54mbps actually reminds me of). TCP是一个简单的选择,但由于不可预测的延迟,抖动和快速重启,通常不鼓励实时流式传输,当涉及无线链路时(54mbps实际上让我想起)当然可以避免。 SCTP can be an better suited alternative, but there are many more (eg MPEG-TS, RSTP, ...). SCTP可能是更适合的替代方案,但还有更多(例如MPEG-TS,RSTP,......)。 Finally, you always could built your own protocol for retransmission of missed/erroneous frames based on UDP, but that is not a trivial task. 最后,您始终可以构建自己的协议,以便根据UDP重新传输错过/错误的帧,但这不是一项简单的任务。

Edit: you could always take a look at VNC/NX implementations, these could help you along also if the images are not fast-changing. 编辑:您可以随时查看VNC / NX实现,如果图像没有快速变化,这些可以帮助您。

  • Actually it seems like you have a wireless connection with capability of 54Mbps. 实际上,您似乎拥有54Mbps的无线连接。 If it is, you have another problem which is that this connection is Half-Duplex. 如果是,您还有另一个问题,即此连接是半双工。 So, in that case, consider your network's bandwidth as 27Mbps. 因此,在这种情况下,请考虑您的网络带宽为27Mbps。
  • Also, in wireless networks, the latency is increased which reduce TCP performance. 此外,在无线网络中,延迟增加,这降低了TCP性能。
  • You can try OpenCV libraries for fast image compression. 您可以尝试使用OpenCV库进行快速图像压缩。 They both provide lossy and lossless compression option (JPEG, PNG, etc..) 它们都提供有损和无损压缩选项(JPEG,PNG等)。
  • You can try to send only the changes, if your streaming image is not changing too fast. 如果您的流媒体图像变化不是太快,您可以尝试仅发送更改。 You can use VLC libraries and OpenCV libraries to find this change data. 您可以使用VLC库和OpenCV库来查找此更改数据。

Not a real concrete answer, but some tips: 不是一个真正具体的答案,但一些提示:

Use TCP. 使用TCP。 For data transfer it is much faster because all the checking and resending of packages is built-in and super-fast. 对于数据传输,速度要快得多,因为所有包的检查和重新发送都是内置且超快的。 Heck, it was invented for data transfer . 哎呀,它是为数据传输发明的 Only use UDP if you need to send a lot of single packages real-time like in a FPS game. 如果您需要像FPS游戏中那样实时发送大量单个包,请仅使用UDP。

Use a fast lossless compression algorithm, something like FastLZ (I just found it using Google, I have no experience with it). 使用快速无损压缩算法,比如FastLZ (我刚刚使用Google发现它,我没有经验)。 It won't work as good a pure lossy image compression algorithm that has certain "advantages" by knowing that it's working with images, but it will work with any kind of data and compress it. 它不会像纯粹的有损图像压缩算法那样工作,因为它知道它处理图像有一定的“优势”,但它可以用于任何类型的数据并压缩它。

Depending of the data you are transferring, you might consider sending only the changes between an image and the next one. 根据您传输的数据,您可能会考虑仅在图像和下一个图像之间发送更改。 This might be useful for a remote desktop, but useless for video. 这可能对远程桌面有用,但对视频无用。 You might help by telling a bit more accurately what kind of data you are sending. 您可以通过更准确地告诉您要发送的数据类型来提供帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM