簡體   English   中英

boost asio udp socket async_receive_from不會調用處理程序

[英]boost asio udp socket async_receive_from does not call the handler

我想創建一個自治線程,專門用於使用boost庫(asio)從UDP套接字接收數據。 該線程應該是由UDP套接字接收的一些數據觸發的無限循環。 在我的應用程序中,我需要使用異步接收操作。

如果我使用同步函數receive_from,一切都按預期工作。

但是,如果我使用async_receive_from,則永遠不會調用處理程序。 由於我使用信號量來檢測是否已收到某些數據,因此程序會鎖定並且永遠不會觸發循環。

我已經驗證(使用網絡分析器)發送方設備正確地在UDP套接字上發送數據。

我已在以下代碼中隔離了該問題。

#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是首選,但是出於調試目的,我使用了阻塞等待,如上面的代碼所示。

我錯過了什么? 我的錯誤在哪里?

您對io_service.run()調用正在退出,因為io_service沒有工作要做。 然后代碼進入while循環並調用m_socket.async_receive_from 此時io_service沒有運行,它從不讀取數據並調用您的處理程序。

你需要在調用io_service run之前安排工作:

即:

// 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));

處理函數將執行以下操作:

// 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;
}

然后你的線程只是等待信號量:

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

筆記:

  1. 你真的需要這個額外的線程嗎? 處理程序是完全異步的,boost :: asio可用於管理線程池(請參閱: think-async
  2. 請不要使用下划線,然后使用國會大廈字母表示變量/功能名稱。 它們是保留的。

m_io_service.run()立即返回,因此沒有人調度完成處理程序。 請注意, io_service::run是基於asio的應用程序的一種“消息循環”,只要您希望asio功能可用,它就應該運行(這是一個簡單的描述,但它對您的情況來說已經足夠了) 。

此外,您不應該在循環中調用async.operation。 相反,在前一個完成處理程序中發出后續的async.operation - 以確保2個async.reads不會同時運行。

請參閱asio示例以查看典型的asio應用程序設計。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM