Клиент сервера быстрой передачи данных (изображений) с помощью Boost Asio - PullRequest
5 голосов
/ 25 июля 2011

Я относительно новичок в сетевом программировании и у меня есть несколько вопросов о передовых практиках непрерывной быстрой передачи данных (изображений) между клиентом и сервером с помощью Boost Asio.Важный момент, мы не можем применять сжатие, которое снижает качество изображения.Мы используем выделенную сеть (54 Мбит) без трафика, кроме нашего.Нам рекомендовали использовать Boost Asio, так как он, кажется, подходит для наших нужд.Тем не менее, поскольку Boost является мощным средством, это сложно для неопытных (Boost) разработчиков, таких как я.

Мы хотим разработать как можно более простой инструмент, который бы непрерывно передавал непрерывно данные изображения между клиентом и пользователем.сервер.В основном это потоковое.Мы бы предпочли использовать TCP, но если бы у нас был значительный прирост производительности с UDP, мы бы не возражали против потери пакетов данных время от времени.

Данные представляют собой беззнаковый буфер символов (640x480px = 307200 байт = 2,34).MBit, монохромный).

Я начал с учебников по Asio и поиграл с проектами sync, async, UDP, TCP.На данный момент я могу отправлять данные с ~ 10fps, ~ 0,1 мс на изображение с TCP и ~ 13fps с UDP.Это слишком медленно.Я ожидал, что отправка 2,4 Мбит в сети 54 Мбит будет быстрее.

Сегодня я не использую сериализацию, архивирование, сжатие (zip) и т. Д. Моих данных.Я думаю, что это улучшит передачу, но мне интересно, должен ли я уладить свои ожидания и / или должен ли я полностью изменить свой подход?

Является ли сериализация данных подходом для потоковой передачи данных сAsio?Сжатие почтового индекса улучшит передачу вероятно значительно?Существуют ли альтернативные подходы или структуры?

Пример кода 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 ]

2 голосов
/ 14 мая 2012

Похоже, вы сравниваете размер кадра (2,34 Мбит / с) со скоростью сети (54 Мбит / с). Если это так, и вы получаете 10 кадров в секунду, ваша фактическая скорость составляет 23,4 Мбит / с - что не так уж плохо при соединении со скоростью 54 Мбит / с.

В любом случае, пожалуйста, сообщите нам, с каким дизайном вы пришли.

Спасибо.

1 голос
/ 25 июля 2011

Если пропускная способность является проблемой, и у вас достаточно процессора, посмотрите на x264 , у него есть схема без потерь, которая сжимается довольно хорошо и быстро.Если процессор более ограничен, взгляните на libz или даже простую библиотеку PNG.Imho с хорошими высокоуровневыми библиотеками, это не так сложно реализовать, часто это всего лишь несколько вызовов функций, и у вас есть ваши данные.

Что касается надежности данных.TCP - это простой выбор, но его часто не поощряют для потоковой передачи в реальном времени из-за непредсказуемых задержек, дрожания и быстрого перезапуска, которых, конечно, можно избежать, когда используется беспроводная связь (о которой 54 Мбит / с на самом деле напоминает мне).SCTP может быть более подходящей альтернативой, но их гораздо больше (например, MPEG-TS, RSTP, ...).Наконец, вы всегда можете создать свой собственный протокол для повторной передачи пропущенных / ошибочных кадров на основе UDP, но это не тривиальная задача.

Редактирование: вы всегда можете взглянуть на реализации VNC / NX, они могутпомочь вам, если изображения не меняются быстро.

0 голосов
/ 21 октября 2013
  • На самом деле кажется, что у вас есть беспроводное соединение с пропускной способностью 54 Мбит / с.Если это так, у вас есть другая проблема, которая заключается в том, что это соединение является полудуплексным.Итак, в этом случае рассмотрите пропускную способность вашей сети как 27 Мбит / с.
  • Кроме того, в беспроводных сетях увеличивается задержка, что снижает производительность TCP.
  • Вы можете попробовать библиотеки OpenCV для быстрого сжатия изображений.Они оба предоставляют возможность сжатия с потерями и без потерь (JPEG, PNG и т. Д.)
  • Вы можете попытаться отправить только изменения, если потоковое изображение не меняется слишком быстро.Вы можете использовать библиотеки VLC и OpenCV, чтобы найти данные об этих изменениях.
0 голосов
/ 25 июля 2011

В зависимости от данных, которые вы передаете, вы можете рассмотреть возможность отправки только изменений между изображением и следующим. Это может быть полезно для удаленного рабочего стола, но бесполезно для видео. Вы могли бы помочь, немного точнее сообщив, какие данные вы отправляете.

0 голосов
/ 25 июля 2011

Не настоящий конкретный ответ, но несколько советов:

Использовать TCP. Для передачи данных это намного быстрее, потому что все проверки и повторная отправка пакетов являются встроенными и очень быстрыми. Черт, это было изобретено для передачи данных . Используйте UDP только в том случае, если вам нужно отправлять много отдельных пакетов в режиме реального времени, как в игре FPS.

Используйте алгоритм быстрого сжатия без потерь, например, FastLZ (я только что нашел его с помощью Google, у меня нет опыта работы с ним). Он не будет работать так же хорошо, как алгоритм сжатия изображений с потерями, который имеет определенные «преимущества», зная, что он работает с изображениями, но он будет работать с любыми данными и сжимать их.

...