The boost::asio (which means asynchronous input/output) library, is quite powerful library for asynchronous i/o, but it could be a bit difficult at first to figure out how to do a normal synchronous read. So, as a reminder for my future-me, and for you, this snippet it’ll be very useful to accomplish that. Probably there will be another ways for doing that, but this is how I managed to do it:
using namespace boost::asio; using namespace boost::system; using boost::optional; ip::tcp::socket _socket; // it could be another kind of socket, not only ip::tcp /** * Dumb function to be used as handler argument and save the error_code * into a pointer * * e.g.: boost::bind( &set_result, some_pointer, _1 ) */ void set_result( optional<error_code>* a, error_code b ) { a->reset( b ); } #define TIMEOUT 60 /** * it uses _socket * if timeout happends throw a system_error exception */ template<typename MutableBufferSequence> optional<error_code> read_with_timeout( const MutableBufferSequence& buffer ) throw( system_error ) { optional<error_code> timer_result; optional<error_code> read_result; deadline_timer timer( _socket.io_service() ); timer.expires_from_now( seconds(TIMEOUT) ); timer.async_wait( boost::bind(&set_result, &timer_result, _1) ); boost::asio::async_read( _socket, buffer, boost::asio::transfer_at_least( buffer_size_helper(buffer) ), boost::bind( &set_result, &read_result, _1 ) ); _socket.io_service().reset(); while ( _socket.io_service().run_one() ) { if ( read_result ) { timer.cancel(); } else if ( timer_result ) { _socket.cancel(); throw system_error( error_code( errc::timed_out, get_generic_category() ) ); } } return read_result; } |
I hope it will be useful, have fun.