如何复用代码统一使用Boost的socket与serial_port类?
问题描述
我正在开发一个项目,一边学习现代C++和wxWidgets GUI开发,一边打造一款能解决日常问题的应用。这款应用需要支持TCP、UDP、RS232连接,接收纯ASCII数据,还得能同时维持数量不定的多种连接。
最开始我在GitHub上找了TCP客户端和RS232的代码实现了原型,后来根据Stack Overflow的建议改用Boost库,目前用的是boost::asio::ip::tcp::socket和boost::asio::serial_port,UDP还没开始研究。
当处理逻辑需要变更时,我得在多处修改代码,所以想遵循*DRY(Don't Repeat Yourself)*原则优化,但发现这两个类虽然接口相似(同步读写语法完全一致),却没有继承自通用的流类,找不到在代码里统一使用它们的最优方式。
我试过几种方法,想写出统一的连接创建和工作线程运行函数,但都没成功,而且多数方法我也没完全搞懂原理:
- 模板
boost::any返回类型std::variant返回类型void*及union
目前我用来接收、重新缓冲和处理数据的模板函数基本符合预期,代码如下:
template <class Handle> bool receiveData(Handle& handle){ std::string line_buffer(""); boost::system::error_code error; boost::asio::streambuf receive_buffer(SERIAL_BUF_SIZE); std::size_t bytes_transferred = boost::asio::read(handle, receive_buffer, boost::asio::transfer_at_least(1), error); if(error && error !=boost::asio::error::eof){ std::cout << "\x1b[31;1mError receiving data\x1b[0m" << std::endl; return false; } else { const char* temp_data = boost::asio::buffer_cast<const char*>(receive_buffer.data()); std::string new_data(temp_data, temp_data+bytes_transferred); receive_buffer.consume(bytes_transferred); persistent_buffer << new_data; persistent_buffer >> std::ws; while(std::getline(persistent_buffer, line_buffer, '\r')){ if(persistent_buffer.eof()) break; persistent_buffer >> std::ws; if(not line_buffer.empty()){ updateLiveData(line_buffer); line_buffer.clear(); } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } if(persistent_buffer.eof()){ persistent_buffer.clear(); persistent_buffer.str({}); persistent_buffer << line_buffer; } return true; } }
我希望能实现socket和serial_port的大致互换使用,类似下面代码的效果,但因为经验不足找不到方法。目前我的简单实现能正常运行,但连接创建部分有重复代码:
while(not this->mustDie.load()){ boost::asio::io_service io_service; boost::system::error_code error; /* TCP版本的代码除了这段之外完全一致 */ boost::asio::serial_port port(io_service); port.open("COM"+com_num, error); port.set_option(boost::asio::serial_port_base::baud_rate(stoi(baudrate))); //////////////////////////////////////////////////////////// if(error) { std::cout << error.message() << std::endl; std::this_thread::sleep_for(CONNECTION_TIMEOUT); continue; } boost::asio::write(port, boost::asio::buffer(QUERY), error); while(receiveData(port) and not this->mustDie.load()){ std::this_thread::sleep_for(std::chrono::milliseconds(500)); } }
内容的提问来源于stack exchange,提问作者Allan Menefee
相关产品推荐
相关产品推荐

