以高数据速率发送图像数据超过提升::asio::udp?



我有4MB大的图像,必须通过以太网发送。 这些映像来自生成映像的一台计算机 X86_64,并发送到另一台计算机 ARM。 图像以两位数的帧速率生成,我使用 Cat 6a 电缆来确保我可以以合理的速度获得足够的数据。我无法理解 boost 允许我使用哪种实用程序通过 UDP 发送任意大小的数据,并在另一端接收它。 两台计算机都安装了Boost,都是linux(但发行版不同)。单个图像丢失并不是那么重要,但发送或拒绝整个图像很重要。

  • 我是否必须手动分段要发送的数据?
  • 如果是这种情况,如何处理图像数据包丢失? 就像我如何能够知道我的图像的结尾是什么?我是否必须用每个数据包对应的图像行标记每个数据包?
  • boost是否有实用程序来处理通过UDP发送的任意数据?

在尝试这样做之后(用行标识符标记每一行),似乎我正在过度饱和一些缓冲区(标签是连续的,直到某个点,它们开始单调地跳跃,所以没有重新排序,但数据包丢失)请注意,这是在本地主机上,所以我不确定我应该期待什么。

我似乎找不到解决大量图像丢失的方法,但我不确定这是否仅仅是因为某些网络电缆限制(尽管在本地主机上发送和接收?

我会迁移到TCP,但我需要确保我可以通过另一端的直接以太网连接可靠地获得200MB/s。图像开始发送之前的时间不如给定秒内的总吞吐量重要。

我为此编写的代码略有简化:

发送图像

// sender.cpp
#include <thread>
#include <chrono>
#include <algorithm>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include "PgmImage.h"
using boost::asio::ip::udp;
const std::string &host = "localhost";
const std::string &port = "8000";
const int image_width = 2048;
const int image_height = 2048;
int main() {
try {
boost::asio::io_service io_service;
udp::resolver resolver(io_service);
udp::resolver::query query(udp::v4(), host, port);
udp::endpoint receiver_endpoint = *resolver.resolve(query);
udp::socket send_socket(io_service);
send_socket.open(udp::v4());
boost::array<std::uint16_t, 2> send_header_buffer;
boost::array<std::uint8_t, image_height + 2> send_row_buffer;
auto time1 = std::chrono::high_resolution_clock::now();
for (int j = 0; j < 1000; ++j) {
for (const auto &file_path : file_path_list) {
// reads in image and has a vector member of char. 
PgmP5Image image("../short_armcam_clip/" + file_path);
send_header_buffer = {image.width(), image.height()};
send_socket.send_to(boost::asio::buffer(send_header_buffer), receiver_endpoint);
for (std::uint16_t i = 0; i < image_height; i++) {
send_row_buffer[0] = static_cast<std::uint8_t>(i >> 8);
send_row_buffer[1] = static_cast<std::uint8_t>(i);
std::copy(&image.getRawBytes()[i * image_width],
&image.getRawBytes()[i * image_width + image_width], &send_row_buffer[2]);
send_socket.send_to(boost::asio::buffer(send_row_buffer), receiver_endpoint);
if (i % 64 == 0) {
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(1));
}
}
}
}
auto time2 = std::chrono::high_resolution_clock::now();
std::cout << "took : " << std::chrono::duration_cast<std::chrono::milliseconds>(time2 - time1).count() << "millis"
<< std::endl;
}
catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
return 0;
}

接收图像

// receiver.cpp
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <iostream>
using boost::asio::ip::udp;
int main() {
try {
boost::asio::io_service io_service;
udp::socket socket(io_service, udp::endpoint(udp::v4(), 8000));
udp::endpoint remote_endpoint;
boost::array<std::uint16_t, 2> recv_header_buffer;
boost::array<std::uint8_t, 2050> recv_row_buffer;
int num_recieved = 0;
while (true) {
boost::system::error_code error;
socket.receive_from(boost::asio::buffer(recv_header_buffer), remote_endpoint, 0, error);
if (error && (error != boost::asio::error::message_size)) {
throw boost::system::system_error(error);
}
int width = recv_header_buffer[0];
int height = recv_header_buffer[1];
std::cout << "width : " << width << " height : " << height << std::endl;
for (int i = 0; i < height; ++i) {
socket.receive_from(boost::asio::buffer(recv_row_buffer), remote_endpoint, 0, error);
if (error && (error != boost::asio::error::message_size)) {
throw boost::system::system_error(error);
}
std::uint16_t row = (recv_row_buffer[0] << 8) + recv_row_buffer[1];
std::cout << "row : " << row << " processed " << std::endl;
std::cout << "i : " << i << std::endl;
if (row != i) {
break;
}
if (i == 2047) {
num_recieved += 1;
std::cout << "Num received: " << num_recieved << std::endl;
}
}
}
}
catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
}
  • 我是否必须手动分段要发送的数据?

是的,你愿意。您应该对它们进行分段,以便每个段都适合以太网数据包(1536 字节 - 以太网 + ip + udp 标头),这有点不方便,但所有段都可以作为向量在 asio::buffer 中传递给 async_write()。

  • 如果是这种情况,如何处理图像数据包丢失? 就像我如何能够知道我的图像的结尾是什么?我是否必须用每个数据包对应的图像行标记每个数据包?

您必须对每个数据包进行编号,一个数据包 # 就足够了,但您的错误处理最终可能会使您的传输速度比 tcp 慢。

  • boost是否有实用程序来处理通过UDP发送的任意数据?

据我所知,Boost没有任何现成的设施可以帮助您通过UDP流式传输数据。

我认为你最好的选择是使用TCP,它处理流以获得最大的刺激,并为你的数据完整性提供一些额外的保险。

  • 我会迁移到TCP,但我需要确保我可以通过另一端的直接以太网连接可靠地获得200MB/s。图像开始发送之前的时间不如给定秒内的总吞吐量重要。

只有一种方法可以检查这一点,那就是通过网络在实际主机和目标之间运行测试。 该问题的答案取决于网络硬件和拓扑、NIC 设备驱动程序和计算机负载。

请注意,TCP 可能会为您提供尽可能高的吞吐量。您不必自己将数据分割成数据包,然后您可以从boost::asio获得最大可能的性能。

最新更新