Boost ASIO UDP 套接字async_receive_from不调用处理程序
boost asio udp socket async_receive_from does not call the handler
我想创建一个自治线程,专门用于使用升压库(asio)从UDP套接字接收数据。此线程应是由从 UDP 套接字接收的某些数据触发的无限循环。在我的应用程序中,我需要使用异步接收操作。
如果我使用同步函数receive_from一切都按预期工作。
但是,如果我使用async_receive_from则永远不会调用处理程序。由于我使用信号量来检测已接收到某些数据,因此程序锁定并且永远不会触发循环。
我已经验证(使用网络分析器)发送方设备是否正确发送了UDP套接字上的数据。
我已经在下面的代码中隔离了这个问题。
#include <boostarray.hpp>
#include <boostasio.hpp>
#include <boostthread.hpp>
#include <boostinterprocesssyncinterprocess_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
没有运行ergo,它永远不会读取数据并调用您的处理程序。
您需要在调用 run 之前安排要执行的工作io_service:
即:
// 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);
}
笔记:
- 你真的需要这个额外的线程吗?处理程序是完全异步的,boost::asio 可用于管理线程池(请参阅:think-async)
- 请不要在变量/函数名称中使用后跟大写字母的下划线。他们是保留的。
m_io_service.run()
立即返回,因此没有人调度完成处理程序。请注意,io_service::run
是基于 asio 的应用程序的一种"消息循环",只要您希望 asio 功能可用,它就应该运行(这是一个有点简化的描述,但对于您的情况来说已经足够了)。
此外,您不应该在循环中调用 async.operation。相反,在前一个完成处理程序中发出后续的 async.operation,以确保 2 个 async.read 不会同时运行。
请参阅 asio示例以查看典型的 asio 应用程序设计。
- 为什么我的 IExtractIcon 处理程序没有被调用?
- 如何使用对C函数和类对象的外部调用来处理C++头文件
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- 未调用 signal() 指定的处理程序
- 如何调用处理程序
- Java(或C++)如何处理接口中定义的方法的调用
- ESP-CoAP 服务器调用资源处理程序,不接收包
- 是否有可以处理方法调用依赖关系的设计模式?
- 异步操作的 Asio 处理程序在其同步对应项正常工作时不会调用
- cmake:生成批处理文件调用cl.exe
- boost::asio 使用 post() 时没有调用处理程序,当直接调用函数时有效(io_context有工作)
- Boost ASIO UDP 套接字async_receive_from不调用处理程序
- Asio在包含处理程序的类被破坏后调用处理程序
- boost::asio::tcp::socket 关闭并取消而不调用处理程序
- 使用系统调用处理退出状态
- boost::asio::d eadline_timer renew仍然调用处理程序函数
- 调用处理程序数据的垃圾收集
- boost::asio::d eadline_timer 不调用处理程序
- 当 asio::async_write 不调用处理程序时该怎么办?