UDP-связь с использованием Boost (для s-функции MATLAB)

Я пытаюсь создать s-функцию (используя библиотеку C++ Boost) для связи по UDP.

Реализация отправителя была довольно простой, 15 минут работы. Я изо всех сил пытаюсь заставить приемник работать.

Я создал следующее в Visual Studio:

#define _WIN32_WINNT 0x0501
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING 

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <stdio.h>

typedef unsigned char   UINT8;
typedef unsigned short  UINT16;

using boost::asio::ip::udp;
using namespace std;

std::vector<char>       receive_buffer;

void process_received_frame(const boost::system::error_code& error, size_t received_frame_size) {
    if (error) {
        cout << "Receive failed: " << error.message() << "\n";        
        return;
    }

    size_t ByteCount = 0;

    std::cout << endl << "Received byte stream (Handler) [" << received_frame_size << "]: ";
    for (std::vector<char>::const_iterator iter = receive_buffer.cbegin(); iter != receive_buffer.cend(); iter++)
    {
        ByteCount++;

        printf("%02X ", (UINT8)*iter);

        if (ByteCount == received_frame_size)
        {
            break;
        }
    }
    std::cout << endl;
}

int main(int argc, char *argv[])
{
    boost::asio::io_service io_service;
    udp::socket             socket(io_service);   
    udp::endpoint           remote_endpoint = udp::endpoint(boost::asio::ip::address_v4::from_string("127.0.0.1"), 19001);

    socket.open(udp::v4());
    socket.bind(udp::endpoint(remote_endpoint));   

    receive_buffer.resize(255);

    try
    {
        socket.async_receive_from(boost::asio::buffer(receive_buffer),
            remote_endpoint,
            boost::bind(&process_received_frame, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
    catch (const std::exception& exp)
    {
        printf("%s\n", exp.what());
    }

    //io_service.poll();
    io_service.run();

    cout << "End";

    std::cin.ignore();
}

Я попытался отправить UDP на localhost:19001 от Simulink и смог получить пакеты UDP в Visual Studio. Обработчик (process_received_frame) вызывается, и все, кажется, работает, как и ожидалось.

Но, учитывая, что io_service::run() работает в режиме блокировки, он приостанавливает выполнение, если на порт 19001 ничего не поступает. Поэтому я попытался использовать io_service::poll() (прокомментировано в коде выше). Однако когда я использую poll(), он не выполняет обработчик. Если я пытаюсь отобразить содержимое 'receive_buffer' из main(), я получаю все 0. Интересно, что когда я пошагово выполняю код для доступа к элементам receive_buffer, я получаю правильные значения.

Не уверен, что я делаю не так. Вполне вероятно, что это ошибка школьника.

Когда я преобразовываю это в s-функцию для MATLAB-Simulink, она делает то же самое - все нули.

Любая помощь приветствуется.

Ура,

1 ответ

Решение

В вашей функции обработчика вам нужно вызвать socket.async_receive_from в конце после обработки ответа. io_service.run() возвращает, когда в его очереди обработки больше нет обработчика.

Посмотрите пример с boost doc здесь: пример сервера синхронизации udp

РЕДАКТИРОВАТЬ

Перечитывая ваш вопрос / комментарий, я не уверен, каков ваш ожидаемый результат или поведение.

Если вы ожидаете только один кадр UDP, то, возможно, позвоните io_service.run_one(),

Если не хочешь run() чтобы заблокировать ваш основной поток, вам нужно запустить другой поток для вызова run(), Что-то вроде:

boost::asio::io_service io_service;
// Process handlers in a background thread.
boost::thread t(boost::bind(&io_service::run, &io_service));  
...

io_service::run() всегда блокирующий вызов. Обработчики завершения могут вызываться только из потоков, вызывающих в данный момент run(), Единственный раз run() будет возвращаться, когда в очереди больше нет обработчиков (вы перестали звонить async_receive) или если вы явно отмените run() командовать по телефону stop() или же reset()

Другие вопросы по тегам