Problem z zastosowaniem boost::asio::ip::udp::socket



  • Witając wszystkich proszę jednocześnie o pomoc w kwestii następujacej

    Jestem właśnie w trakcie realizacji projektu pisanego w Qt, którego zadaniem jest
    odbiór sporej porcji danych UDP. Źródło umieszczone na lokalnej maszynie generuje
    te dane z prędkością ok 20MBps. Na początku realizacji projektu używałem obiektu
    klasy QUdpSocket ale szybko zorientowałem się, że jest on bardzo wolny i nie nadaje
    się do odbioru tylu danych. Pogrzebałem trochę po forach, w których potwierdzono moje
    przypuszczenia - QUdpSocket jest powolny. Jednocześnie poradzono aby skorzystać z
    boost::asio::ip::udp::socket lub gołego socketa (?).
    Włączyłem odpowiednie biblioteki do QtCreatora i napisałem kod posiłkując się tutorialem
    ze strony http://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tutorial/tutdaytime6.html.
    Natrafiłem jednak na kolejne problemy.
    Struktura projektu w Qt nie jest adekwatna do kodu z tutoriala.

    Mój kod:
    @int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    oscilloscope::Oscilloscope w;
    w.show();

    return a.exec();
    

    }

    @
    oscilloscope.h:

    @class Oscilloscope
    {
    ...
    boost::asio::io_service io_serv;
    UdpReceiver *port1;
    ...
    }
    @

    oscilloscope.cpp

    @oscilloscope::oscilloscope()
    {
    ...........
    try
    {
    port1 = new UdpReceiver(io_serv);
    io_serv.run(); // <- ważne
    }
    catch(std::exception& e)
    {
    std::cerr << e.what() << "\n";
    }
    ...........
    }
    @

    udpreceiver.h

    @class UdpReceiver
    {
    udp::socket sockPort;
    udp::endpoint remote_endpoint;
    boost::array<char, 1> rec_buffer;

    public:
    UdpReceiver(boost::asio::io_service & io_serv);

    private:
    void StartReceive();
    void handle_receive(const boost::system::error_code& error,
    std::size_t bytes_transferred);
    };
    @

    udpreceiver.cpp

    @
    UdpReceiver::UdpReceiver(boost::asio::io_service & io_serv):
    sockPort(io_serv, udp::endpoint(udp::v4(), 7755))
    {
    StartReceive();
    }

    void UdpReceiver::StartReceive()
    {
    sockPort.async_receive_from(
    boost::asio::buffer(rec_buffer), remote_endpoint,
    boost::bind(&UdpReceiver::handle_receive, this,
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred));

    }

    void UdpReceiver::handle_receive(const boost::system::error_code& error,
    std::size_t bytes_transferred)
    {
    if (!error || error == boost::asio::error::message_size)
    {
    std::string err = error.message();
    StartReceive();
    }
    else
    {
    std::string ss = error.message();
    std::cerr << ss << " " << error.value() << "\n";

    StartReceive();
    }
    }
    @

    Program prawidłowo wchodzi do funkcji handle_receive gdy pojawią się jakieś dane
    ale pierwszy warunek jest zawsze false. Zatem realizowany jest drugi warunek (else)
    gdzie wypisywany jest numer błędu 234 - More data is available.
    Co to oznacza?
    Gdzie robię błąd?
    Czy ktoś mógłby pomóc?
    Czy to istotnie jest prawda, że QUdpSocket jest aż tak powolny?

    Z góry dziękuję za pomoc i pozdrawiam
    Miłosz



  • To forum wygląda na mocno nieżywe, albo nikt ci nie chce odpowiedzieć bo to jest porostu głupie, w każdym bądź razie...

    Dziwne bo nie znalazłem na twój temat nic dlaczego dostajesz kod błędu 234 zamiast 90. Tak powinieneś dostawać boost::asio::error::message_size ponieważ próbujesz wczytać wiadomość do bufora o długości jednego znaku. Maksymalnie pakiet może nawet wynieść 64k więc powinieneś go zwiększyć.

    Czytając po jednym znaku, zazwyczaj twój kod będzie wolny. Więc wcale się nie dziwię że QUdpSocket był dla ciebie wolny.

    Osobiście nie zauważyłem znaczącej różnicy między ASIO a Qt5, co najwyżej kilka procent na rzecz asio. Przynajmniej przy co najwyżej kilku gniazdach i jednym wątku, nie ma żadnej różnicy.

    Co do integracji Qt z ASIO to jest konkretny problem. Najfunkcjonalniejsza jest integracja io_service w pętli QThread, ale to dość kłopotliwe i nie widziałem do tego dobrej gotowej implementacji.
    Wydaje się że najłatwiej jest stworzyć zwykły wątek boost::thread a obiektami z Qt komunikować się do Qt za pośrednictwem QInvokeMethod oraz w przeciwnym kierunku z is_service::post (ewentualnie io_service::strand).


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.