2017-06-22 79 views
0

我有4MB的圖像,必須通過以太網發送。圖像來自一臺計算機,X86_64,它生成它們,併發送到另一臺計算機,ARM。圖像以兩位數幀速率生成,我使用cat 6a電纜確保以合理的速度獲得足夠的數據。我無法理解什麼樣的實用程序提升可讓我使用通過UDP發送任意大小的數據,並在另一端接收它。兩臺電腦都安裝了Boost,兩者都是linux(但不同的發行版)。個人圖像丟失並不重要,但重要的是要發送或拒絕整個圖像。通過boost :: asio :: udp以高數據速率發送圖像數據?

  • 我是否必須手動分段要發送的數據?
  • 如果是這種情況,我該如何處理圖像丟包?就像我將如何分辨我的圖像的結尾是什麼?我是否必須爲每個數據包添加與其對應的圖像行?
  • 增強是否有實用程序來處理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; 
    } 
} 

回答

1
  • 我必須手動分段數據發送結束了嗎?

是的,你這樣做。你應該對它們進行細分,使每個段適合以太網數據包(1536字節 - 以太網+ ip + udp頭),這有點不方便,但是所有段可以作爲矢量在asio :: buffer中傳遞給async_write ()。

  • 如果是這種情況,我該如何處理圖像丟包?就像我將如何分辨我的圖像的結尾是什麼?我是否必須爲每個數據包添加與其對應的圖像行?

你將不得不號每個數據包,數據包#就足夠了,但你的錯誤處理可能會最終使你的傳輸比TCP慢。

  • 增強是否有實用程序來處理UDP上的任意數據發送?

升壓沒有,據我所知有任何現成的設施,這將有助於你在UDP流數據。

我認爲您最好的選擇是使用TCP,它可以處理流式傳輸以最大限度地提高速度,併爲您提供一些額外的數據完整性保障。

  • 我移動到TCP,但我需要得到保證,我可以通過在可靠的另一端直接以太網連接獲得200MB /秒。圖像開始發送之前的時間並不比給定秒內的整體吞吐量重要。

只有一個檢查這種方式,並且運行在你的網絡測試,實際的主機和目標之間。這個問題的答案取決於網絡硬件和拓撲,NIC設備驅動程序和機器負載。

請注意,TCP可能會爲您提供最高的吞吐量。您不必將自己的數據分段爲數據包,然後您可以從boost :: asio獲得最大可能的性能。

+0

經過測試TCP之後,我獲得了奇怪的性能提升,所以我現在切換到TCP – snb

+0

這是因爲TCP確實是流式傳輸。您可以通過使用套接字TCP窗口大小來優化您的應用程序以獲得最佳吞吐量。 https://stackoverflow.com/questions/14381303/increasing-tcp-window-size –