Reputation: 591
I am building an HTTP client based on the example on HTTP server given at boost website. Now, the difference between that code and mine is that the example uses the server constructor to start the asynchronous operations. This makes sense since a server is supposed to listen all the time. In my client, on the other hand, I want to first construct the object and then have a send()
function that starts off by connecting to the endpoint and later on sends a request and finally listens for the reply. This makes sense too, doesn't it?
When I create my object (client) I do it in the same manner as in the server example (winmain.cpp). It looks like this:
client c("www.boost.org);
c.start(); // starts the io_service in a thread
c.send(msg_);
The relevant parts of the code are these:
void enabler::send(common::geomessage& msg_)
{
new_connection_.reset(new connection(io_service_,
connection_manager_,
message_manager_, msg_
));
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(host_address, "http");
resolver.async_resolve(query, boost::bind(
&enabler::handle_resolve,
boost::ref(*this),
boost::asio::placeholders::error,
boost::asio::placeholders::iterator
));
}
void enabler::run()
{
io_service_.run();
}
The problem with this is that the program gets stuck somewhere here. The last thing that prints is the "Resolving host", after that the program ends. I don't know why because the io_service
should block until all async operations have returned to their callbacks. If, however, I change the order of how I call the functions, it works. If I call run()
just after the call to async_resolve()
and also omit calling start()
in my main program, it works!
In this scenario, io_service
blocks as it should and I can see that I get a response from the server.
It has something to do from the fact that I call run()
from inside the same class as where I call async_resolve()
. Could this be true? The I suppose I need to give a reference from the main program when I call run()
, is it like that?
I have struggled with getting io_service::work
to work but the program just gets stuck and yeah, similar problems as the one above occur. So it does not really help.
So, what can I do to get this right? As I said earlier, what I want is to be able to create the client object and have the io_service
running all the time in a separate thread inside the client class. Secondly to have a function, send()
, that sends requests to the server.
Upvotes: 1
Views: 297
Reputation: 11245
If you don't expect to have some work at all times, to keep the io_service busy, you should construct an io_service::work
object in some scope which can be exited without io_service::run()
having to return first. If you're running the io_service
in a separate thread, I would imagine you wouldn't have a problem with that.
It's sort of hard to know what you're trying to do with those snippets of code. I imagine that you'd want to do something along these lines:
struct client
{
io_service io_service_;
io_service::work* w_;
pthread_t main_thread_;
client(): w_(new io_service::work(io_service)) { ... }
void start() { pthread_create(&main_thread_, 0, main_thread, this); }
static long main_thread(void* arg) { ((client*)arg)->io_service_.run(); }
// release the io_service and allow run() to return
void stop() { delete w_; w_ = 0; pthread_join(main_thread_); }
};
Upvotes: 0
Reputation: 30031
You need to start at least some work before calling run()
, as it returns when there is no more work to do.
If you call it before you start the async resolve, it won't have any work so it returns.
Upvotes: 2