2012-11-27 11 views
5

Chcę utworzyć autonomiczny wątek poświęcony wyłącznie na odbieranie danych z gniazda UDP za pomocą bibliotek boost (asio). Ten wątek powinien być nieskończoną pętlą uruchamianą przez niektóre dane odebrane z gniazda UDP. W mojej aplikacji potrzebuję użyć asynchronicznej operacji odbierania.doładowanie asio udp socket async_receive_from nie wywołuje programu obsługi

Jeśli korzystam z funkcji synchronicznej receive_from, wszystko działa zgodnie z oczekiwaniami.

Jednak jeśli używam async_receive_from handler nigdy nie jest wywoływana. Ponieważ używam semafora do wykrycia, że ​​niektóre dane zostały odebrane, program blokuje się i pętla nigdy nie jest wyzwalana.

Sprawdziłem (za pomocą analizatora sieci), czy urządzenie wysyłające prawidłowo wysyła dane do gniazda UDP.

Wyizolowałem problem w poniższym kodzie.

#include <boost\array.hpp> 
#include <boost\asio.hpp> 
#include <boost\thread.hpp> 
#include <boost\interprocess\sync\interprocess_semaphore.hpp> 

#include <iostream> 

typedef boost::interprocess::interprocess_semaphore Semaphore; 

using namespace boost::asio::ip; 

class ReceiveUDP 
{ 
public: 

    boost::thread* m_pThread; 

    boost::asio::io_service   m_io_service; 
    udp::endpoint     m_local_endpoint; 
    udp::endpoint     m_sender_endpoint; 

    udp::socket      m_socket; 

    size_t  m_read_bytes; 
    Semaphore m_receive_semaphore; 

    ReceiveUDP() : 
     m_socket(m_io_service), 
     m_local_endpoint(boost::asio::ip::address::from_string("192.168.0.254"), 11), 
     m_sender_endpoint(boost::asio::ip::address::from_string("192.168.0.11"), 5550), 
     m_receive_semaphore(0) 
    { 
     Start(); 
    } 

    void Start() 
    { 
     m_pThread = new boost::thread(&ReceiveUDP::_ThreadFunction, this); 
    } 

    void _HandleReceiveFrom(
     const boost::system::error_code& error, 
     size_t         received_bytes) 
    { 
     m_receive_semaphore.post(); 

     m_read_bytes = received_bytes; 
    } 

    void _ThreadFunction() 
    { 
     try 
     { 
      boost::array<char, 100> recv_buf; 

      m_socket.open(udp::v4()); 
      m_socket.bind(m_local_endpoint); 
      m_io_service.run(); 

      while (1) 
      { 
#if 1 // THIS WORKS 

       m_read_bytes = m_socket.receive_from(
        boost::asio::buffer(recv_buf), m_sender_endpoint); 

#else // THIS DOESN'T WORK 

       m_socket.async_receive_from(
        boost::asio::buffer(recv_buf), 
        m_sender_endpoint, 
        boost::bind(&ReceiveUDP::_HandleReceiveFrom, this, 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred)); 

       /* The program locks on this wait since _HandleReceiveFrom 
       is never called. */ 
       m_receive_semaphore.wait(); 

#endif 

       std::cout.write(recv_buf.data(), m_read_bytes); 
      } 

      m_socket.close(); 
     } 
     catch (std::exception& e) 
     { 
      std::cerr << e.what() << std::endl; 
     } 
    } 
}; 

void main() 
{ 
    ReceiveUDP receive_thread; 

    receive_thread.m_pThread->join(); 
} 

timed_wait na semafora ma być jednak korzystne dla celów debugowania użyłem czekać blokowania jak w powyższym kodzie.

Czy coś mi umknęło? Gdzie jest mój błąd?

Odpowiedz

7

Twoje połączenie z io_service.run() kończy się, ponieważ nie ma pracy do wykonania przez użytkownika io_service. Kod następnie wchodzi do pętli while i wywołuje m_socket.async_receive_from. W tym momencie io_service nie działa poprawnie, nigdy nie odczytuje danych i dzwoni do obsługi.

trzeba zaplanować pracę, aby zrobić przed wywołaniem io_service run:

tj:

// Configure io service 
ReceiveUDP receiver; 

m_socket.open(udp::v4()); 
m_socket.bind(m_local_endpoint); 
m_socket.async_receive_from(
    boost::asio::buffer(recv_buf), 
    m_sender_endpoint, 
    boost::bind(&ReceiveUDP::_HandleReceiveFrom, receiver, 
    boost::asio::placeholders::error, 
    boost::asio::placeholders::bytes_transferred)); 

Handler funkcja będzie wykonać następujące czynności:

// start the io service 
void HandleReceiveFrom(
    const boost::system::error_code& error, 
    size_t received_bytes) 
{ 
    m_receive_semaphore.post(); 

    // schedule the next asynchronous read 
    m_socket.async_receive_from(
     boost::asio::buffer(recv_buf), 
     m_sender_endpoint, 
     boost::bind(&ReceiveUDP::_HandleReceiveFrom, receiver, 
     boost::asio::placeholders::error, 
     boost::asio::placeholders::bytes_transferred)); 

    m_read_bytes = received_bytes; 
} 

Twojego wątku po prostu czeka dla semafora:

while (1) 
{ 
    m_receive_semaphore.wait(); 
    std::cout.write(recv_buf.data(), m_read_bytes); 
} 

Notatki:

  1. Naprawdę potrzebujesz tego dodatkowego wątku? Procedura obsługi jest całkowicie asynchroniczna, a funkcja boost :: asio może być używana do zarządzania pulą wątków (zobacz: think-async)
  2. Nie należy używać podkreśleń, a po nich należy używać litery na literę dla nazw zmiennych/funkcji. Są zarezerwowane.
+0

Dziękuję bardzo! Zmodyfikowałem kod zgodnie z Twoimi sugestiami i wszystko działa dobrze. Skonfigurowałem usługę We/Wy przed utworzeniem wątku. Wezwanie do io_service.run() jest tylko po utworzeniu wątku: \t void start() { \t \t \t m_socket.open (udp :: v4()); \t \t m_socket.bind (m_local_endpoint); \t \t StartRead(); \t \t m_pThread = new boost :: thread (& ReceiveUDP :: _ ThreadFunction, this); \t \t m_io_service.run(); \t} Where StartRead() to połączenie z async_receive_from. Jeszcze raz dziękuję. – arms

+0

Dzięki za to, zwariowałem. – Alex

0

m_io_service.run() zwraca natychmiast, więc nikt nie wysyła instrukcji obsługi ukończenia. Zauważ, że io_service::run jest rodzajem "pętli komunikatów" aplikacji opartej na asio, i powinna działać tak długo, jak długo ma być dostępna funkcja asio (jest to nieco uproszczony opis, ale wystarczająco dobry dla twojego przypadku).

Poza tym nie powinieneś wywoływać operacji async.operation w pętli. Zamiast tego wydaj kolejną operację async.operation w module obsługi zakończenia poprzedniej - aby zapewnić, że 2 async.reads nie będzie działać jednocześnie.

Zobacz przykłady asio, aby zobaczyć typowy projekt aplikacji asio.

Powiązane problemy