Brad,
Here's my code below. Couple of observations:
1. The code is being run on Suse11 but on RHEL6 the behavior is
inconsistent as well.
2. If I run the code disabling epoll things work fine. If I don't
there's an additional reset + run_one required right after async_write
call. This is counter intuitive.
3. Internal handlers, in my humble opinion, should not be something
users should be asked to bother with. From their perspective, it should
only be their completion handlers that they need to think about. In the
code below, the io_service.run_one returns after the call to
async_read_until but it is extremely difficult to understand whose handler
got executed, mine in application code didn't.
4. My compiler is g++-4.3.4. I think Linux kernel version is 2.5+.
#include <iostream>
#include
#include
#include
template <typename T>
T
execute_command(
std::string const & host,
std::string const & port,
int timeout,
std::string const & command,
T const & test_value);
void
execute_command_impl(
std::string const & host,
std::string const & port,
int timeout,
std::string const & command,
boost::asio::streambuf& response);
template <typename T>
T
execute_command(
std::string const & host,
std::string const & port,
int timeout,
std::string const & command,
T const & test_value)
{
if (host.find("test") == 0 && port == "test")
{
return host == "test_ERROR"
? throw std::runtime_error("Intentional test error")
: test_value;
}
std::string current_action;
try {
std::cout << "parsing response: ";
boost::asio::streambuf response;
execute_command_impl(
host, port, timeout, command, response);
std::istream is(&response);
T ans;
is >> ans;
if (is.fail())
{
throw std::runtime_error("Invalid response");
}
return ans;
}
catch (std::exception const & e)
{
void io_handler(
boost::system::error_code const & error,
std::size_t /* bytes_transferred */)
{
if (error)
{
throw std::runtime_error(error.message());
}
}
void
execute_command_impl(
std::string const & host,
std::string const & port,
int timeout,
std::string const & command,
boost::asio::streambuf& response)
{
std::string current_action("initializing asio");
try
{
using namespace boost::asio;
using boost::asio::ip::tcp;
io_service io_service;
deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(timeout));
timer.async_wait(&timer_handler);
std::cout << "resolving " << host << ":" << port << "\n";
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), host, port);
tcp::resolver::iterator iterator;
resolver.async_resolve(
query,
boost::bind(&resolve_handler, boost::ref(iterator), _1, _2));
io_service.reset();
io_service.run_one();
std::cout << "connecting to " << host << ":" << port << "\n";
tcp::socket socket(io_service);
socket.async_connect(*iterator, &connect_handler);
io_service.reset();
io_service.run_one();
std::cout << "writing to " << host << ":" << port << "\n";
async_write(socket, buffer(command), &io_handler);
io_service.reset();
io_service.run_one();
std::cout << "reading from " << host << ":" << port << "\n";
async_read_until(socket, response, '\n', &io_handler);
io_service.reset();
io_service.run_one();
}
catch (std::exception const & e)
{
throw std::runtime_error(current_action + ": " + e.what());
}
}
int main()
{
boost::asio::streambuf response;
std::string host = "localhost";
std::string port = "8977";
int timeout = 50;
std::string command = "login,remote\n";
execute_command(
host,
port,
timeout,
command,
std::string("test"));
std::cout << "" << std::endl;
}
throw std::runtime_error(
"Error performing \""
+ command
+ current_action + ": " + e.what());
}
}
using namespace boost::asio;
using boost::asio::ip::tcp;
void timer_handler(
boost::system::error_code const & /* error */)
{
throw std::runtime_error("Operation timed out");
}
void resolve_handler(
tcp::resolver::iterator & iterator,
boost::system::error_code const & error,
tcp::resolver::iterator resolved)
{
if (error)
{
throw std::runtime_error(error.message());
}
iterator = resolved;
}
void connect_handler(
boost::system::error_code const & error)
{
if (error)
{
throw std::runtime_error(error.message());
}
}
On Thu, May 30, 2013 at 1:56 AM, Brad Higgins wrote:
Arpan,
Thanks Brad. This is likely what is happening since 2 consecutive calls to
io_service.run_one fixed the problem. Note that a single call to
io_service.run did NOT fix the problem.
I do have follow up questions here:
1. What are internal handlers?
2. Where in boost documentation do we mention internal handlers?
3. Is this internal handler business new to boost asio? The 1.44
version always calls my handler after the call to run_one. If yes, since
which version has this been around?
see
http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_rea...
This isn't new.
1. In async-read-until my handler will only get called after the 2nd
call to io_service.run_one. Are there any indications after
io_service.run_one the first time that I need to call the method a second
time?
2. What's a clean way to do async-read-until? Calling run_one twice
looks genuinely messy.
3. Why does the single call to io_service.run not fix the problem? It
too returns 1.
I'm not sure why your io_service.run() fails to fix the problem. The
io_service.run() method will run until there is no more work, or until the
io_service is stopped. Are you stopping the io_service? Are you sure your
handler wasn't called, when it returns 1?
-Brad
--
Regards,
Arpan
-----------------------------------------------------------------------------------------------------------------
Reality is merely an illusion, albeit a very persistent one.