c++ - boost::asio::deadline_timer doesn't call handler -
i have tcp client polls server reply deadline if server cannot reached client not blocked. problem have encountered async_wait
never seems phone call handler, blocking client when fails connect. every phone call tcppoll
have own thread (which why create new io_service
) doesn't seem work without multithreading. also, networkentity
object can phone call tcppoll
more 1 time during lifetime.
my question : blocking deadline_timer
calling handler? (and how prepare it)
here relevant code, working long nil fails (connect, write, read) (sorry if it's bit long) :
void networkentity::stop() { stopped_ = true; //close socket //cancel timeout } void networkentity::check_timeout(const boost::system::error_code& error) { if (stopped_) return; if (timeout_.expires_at() <= boost::asio::deadline_timer::traits_type::now()) { stop(); timeout_.expires_at(boost::posix_time::pos_infin); std::cout << address_ << " timed out\n"; } timeout_.async_wait(boost::bind(&networkentity::check_timeout, this, boost::asio::placeholders::error)); } std::vector<std::string> networkentity::tcppoll(const char* message, const char endofmessage) { boost::asio::io_service io_service; stopped_ = false; timeout_.expires_from_now(boost::posix_time::seconds(timeout_)); timeout_.async_wait(boost::bind(&networkentity::check_timeout, this, boost::asio::placeholders::error)); tcp::resolver resolver(io_service); start_connect(&io_service, resolver.resolve(tcp::resolver::query(address_, port_)), message, endofmessage); io_service.run(); //retrieve reply class //return reply } void networkentity::start_connect(boost::asio::io_service* io_service, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endofmessage) { socket_.reset(new tcp::socket(*io_service)); socket_->async_connect(endpoint_iterator->endpoint(), boost::bind(&networkentity::handle_connect, this, io_service, boost::asio::placeholders::error, endpoint_iterator, message, endofmessage)); } void networkentity::handle_connect(boost::asio::io_service* io_service, const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endofmessage) { if(stopped_) return; if (err) { std::cout << "connect error: " << err.message() << "\n"; stop(); } else { start_write(message, endofmessage); } } void networkentity::start_write(const std::string message, const char endofmessage) { std::ostream request_stream(&request_); request_stream << message; boost::asio::async_write(*socket_, request_, boost::bind(&networkentity::handle_write, this, boost::asio::placeholders::error, endofmessage)); } void networkentity::handle_write(const boost::system::error_code& error, const char endofmessage) { if (stopped_) return; if (!error) { //sleep 500ms allow time reciever process info (had bug on one) start_read(endofmessage); } else { std::cout << "write error : " << error.message() << "\n"; stop(); } } void networkentity::start_read(const char endofmessage) { boost::asio::async_read_until(*socket_, answer_, endofmessage, boost::bind(&networkentity::handle_read, this, boost::asio::placeholders::error)); } void networkentity::handle_read(const boost::system::error_code& error) { if (stopped_) return; if (error) { std::cout << "read error : " << error.message() << "\n"; stop(); } else { stop(); } }
i think must confused multiple instances of io_service.
the reason think because in code never show how initialize timeout_
. , io_service
instance using connection instantiated within tcppoll
function... leads me believe accidentally registering deadline timer on separate io_service don't run?
here's version works, notes:
it has done awaystopped_
boolean, it's unnecessary , bound confuse see new implementation of check_timeout
, stop
on how observe various programme flows the total code, self-contained, few more lines of code posted in question #include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> using tcp = boost::asio::ip::tcp; struct networkentity { boost::asio::io_service io_service; boost::asio::deadline_timer timeout_{io_service}; std::string address_ = "localhost"; std::string port_ = "6767"; int timeout_ = 3; boost::shared_ptr<tcp::socket> socket_; boost::asio::streambuf request_, answer_; void stop() { if (socket_) { socket_->cancel(); socket_->close(); } timeout_.cancel(); io_service.stop(); } void check_timeout(const boost::system::error_code& error) { if (error != boost::asio::error::operation_aborted) { stop(); std::cout << address_ << " timed out\n"; } timeout_.async_wait(boost::bind(&networkentity::check_timeout, this, boost::asio::placeholders::error)); } std::vector<std::string> tcppoll(const char* message, const char endofmessage) { timeout_.expires_from_now(boost::posix_time::seconds(timeout_)); timeout_.async_wait(boost::bind(&networkentity::check_timeout, this, boost::asio::placeholders::error)); tcp::resolver resolver(io_service); start_connect(&io_service, resolver.resolve(tcp::resolver::query(address_, port_)), message, endofmessage); io_service.run(); //retrieve reply class //return reply std::ostringstream oss; oss << &answer_; homecoming { oss.str() }; } void start_connect(boost::asio::io_service* io_service, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endofmessage) { socket_.reset(new tcp::socket(*io_service)); socket_->async_connect(endpoint_iterator->endpoint(), boost::bind(&networkentity::handle_connect, this, io_service, boost::asio::placeholders::error, endpoint_iterator, message, endofmessage)); } void handle_connect(boost::asio::io_service* io_service, const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endofmessage) { if (err) { std::cout << "connect error: " << err.message() << "\n"; stop(); } else { start_write(message, endofmessage); } } void start_write(const std::string message, const char endofmessage) { std::ostream request_stream(&request_); request_stream << message; boost::asio::async_write(*socket_, request_, boost::bind(&networkentity::handle_write, this, boost::asio::placeholders::error, endofmessage)); } void handle_write(const boost::system::error_code& error, const char endofmessage) { if (!error) { //sleep 500ms allow time reciever process info (had bug on one) start_read(endofmessage); } else { std::cout << "write error : " << error.message() << "\n"; stop(); } } void start_read(const char endofmessage) { boost::asio::async_read_until(*socket_, answer_, endofmessage, boost::bind(&networkentity::handle_read, this, boost::asio::placeholders::error)); } void handle_read(const boost::system::error_code& error) { if (error) { std::cout << "read error : " << error.message() << "\n"; } stop(); } }; int main() { networkentity ne; (auto& s : ne.tcppoll("this request", '\n')) { std::cout << "line: '" << s << "'\n"; } }
c++ boost boost-asio
No comments:
Post a Comment