如何用C++17结合Boost ASIO过滤心跳,从TCP流提取有效响应?
优化TCP命令响应过滤与提取的规范方案
你的现有实现存在缓存管理混乱、字符串处理冗余的问题,这里基于C++17和Boost ASIO 1.81.0提供更清晰、可维护的优化方案:
核心优化思路
- 持久化缓存处理粘包:用类成员的
streambuf缓存未解析数据,避免每次读取时丢弃剩余内容 - 分离解析与业务逻辑:把心跳判断、消息提取等通用逻辑抽成独立函数,简化主流程
- 高效字符串操作:用
std::string::find替代迭代器搜索,代码更简洁直观 - 提前错误处理:读取操作后立即检查错误,避免无效后续处理
优化后的代码实现
首先在TCPClient类中添加持久化读取缓存:
class TCPClient { private: boost::asio::ip::tcp::socket* m_socket; boost::asio::streambuf m_read_buffer; // 用于缓存未解析的读取数据 std::string esito_cmd_al_server; // ... 其他成员 };
然后实现核心函数:
#include <string> #include <optional> #include <boost/asio.hpp> // 判断是否为心跳包 bool is_heartbeat(const std::string& msg) { return msg == "{Heartbeat}"; } // 从缓存中提取单个以}结尾的完整消息 std::optional<std::string> extract_single_message(boost::asio::streambuf& buf) { std::string data(boost::asio::buffer_cast<const char*>(buf.data()), buf.size()); size_t close_brace_pos = data.find('}'); if (close_brace_pos == std::string::npos) { return std::nullopt; // 无完整消息,返回空 } // 提取完整消息 std::string msg = data.substr(0, close_brace_pos + 1); // 移除已解析的内容,保留剩余数据在缓存中 buf.consume(close_brace_pos + 1); return msg; } void TCPClient::Send_cmd(std::string data) { boost::system::error_code error; // 发送命令 auto bytes_sent = boost::asio::write(*m_socket, boost::asio::buffer(data), error); if (error) { esito_cmd_al_server = "send failed: " + error.message(); return; } esito_cmd_al_server = "Client sent the command"; // 循环读取直到获取有效响应 for (;;) { // 读取直到遇到}或出错 size_t bytes_read = boost::asio::read_until(*m_socket, m_read_buffer, "}", error); if (error) { esito_cmd_al_server = error == boost::asio::error::eof ? "Connection closed by server" : "Read error: " + error.message(); if (error != boost::asio::error::eof) { throw boost::system::system_error(error); } return; } // 批量处理缓存中的所有完整消息 std::optional<std::string> msg; while ((msg = extract_single_message(m_read_buffer)).has_value()) { if (is_heartbeat(msg.value())) { continue; // 跳过心跳包 } // 找到有效响应,更新状态并退出 esito_cmd_al_server = msg.value(); return; } } }
可选:用JSON库增强响应可靠性
如果服务器响应可以调整为严格JSON格式(比如把{1:ok}改为{"1":"ok"}),可以用nlohmann/json库解析,避免字符串匹配的脆弱性:
#include <nlohmann/json.hpp> using json = nlohmann::json; // 判断是否为有效响应 bool is_valid_response(const std::string& msg) { try { json j = json::parse(msg); // 根据实际响应格式调整判断逻辑 return j.contains("1") && j["1"] == "ok"; } catch (const json::parse_error&) { return false; // 解析失败,不是有效响应 } }
然后在消息处理循环中替换判断逻辑:
while ((msg = extract_single_message(m_read_buffer)).has_value()) { if (is_heartbeat(msg.value())) { continue; } if (is_valid_response(msg.value())) { esito_cmd_al_server = msg.value(); return; } // 非心跳也非有效响应,继续等待下一条消息 }
内容的提问来源于stack exchange,提问作者malloy
相关产品推荐
相关产品推荐

