Boost::Asio deadline timer导致UDP Socket读取阻塞问题求助
问题分析与修复方案
核心问题定位
从代码和运行日志来看,导致定时器触发后接收功能失效的主要原因有两个:
1. 内存越界访问破坏程序状态
handle_incoming函数中错误地将收到的原始数据强制转换为固定长度的array<ResponsePacket, 8>并遍历8个元素,但实际收到的字节数可能不等于8 * sizeof(ResponsePacket)。这种越界访问会破坏内存中的其他变量(比如定时器、socket的内部状态),导致后续接收操作无法正常执行。
2. 重复发起异步接收操作
write函数末尾额外调用了read(),而初始的接收循环已经通过configure中的read()和handle_incoming的递归调用维持。重复发起的接收操作会导致socket上同时存在多个待处理的异步接收任务,引发逻辑混乱,干扰正常的接收流程。
修复代码
修复handle_incoming函数(解决内存越界)
auto PowerSwitch::handle_incoming(const usize bytes) -> void { const size_t packet_size = sizeof(ResponsePacket); // 校验数据长度是否合法 if (bytes % packet_size != 0) { llog::warn("powerswitch: 收到非法数据(长度{}不是{}的整数倍)", bytes, packet_size); return; } const size_t packet_count = bytes / packet_size; const auto raw = span(this->m_buffer).first(bytes); const auto packets = reinterpret_cast<const ResponsePacket*>(raw.data()); for (size_t i = 0; i < packet_count; ++i) { const auto& pkt = packets[i]; // 校验通道号合法性 if (pkt.channel >= m_channels.size()) { llog::warn("powerswitch: 无效通道号{}", pkt.channel); continue; } this->m_channels[pkt.channel] = ChannelData { .voltage = static_cast<f32>(pkt.voltage) / 1000.0f, .current = static_cast<f32>(pkt.current), .enabled = static_cast<bool>(pkt.enabled) }; llog::trace("[通道{}: {} {}V {} mA]", pkt.channel, m_channels[pkt.channel].enabled, m_channels[pkt.channel].voltage, m_channels[pkt.channel].current); } }
修复write函数(移除多余的read调用)
auto PowerSwitch::write(const string_view data) -> void { this->m_socket.async_send_to( asio::buffer(data), this->m_target, [this](const auto& ec, const auto& bytes_transferred) { if(ec) { llog::error("powerswitch: 发送错误: {}", ec.what()); return; } llog::trace("powerswitch: 向{}:{}发送了{}字节", this->m_target.address().to_string(), this->m_target.port(), bytes_transferred ); } ); // 删除此行多余的read()调用 }
可选优化:增强接收错误处理
避免临时错误导致接收循环终止:
auto PowerSwitch::read() -> void { this->m_socket.async_receive_from( asio::buffer(this->m_buffer), this->m_endpoint, [this](const auto& ec, const auto& bytes_transferred) { if(ec) { llog::error("powerswitch: 接收错误: {}", ec.what()); // 非关闭类错误,尝试重启接收 if (ec != asio::error::operation_aborted && ec != asio::error::bad_descriptor) { this->read(); } return; } this->handle_incoming(bytes_transferred); this->read(); } ); }
内容的提问来源于stack exchange,提问作者whs31-
相关产品推荐
相关产品推荐

