boost::asio ioservice holds the rest of my code run - c++

i have created a windows appliation and i have used some QT Gui in that to display a Widget, so now i want to add boost::asio async TCP code to receive and send the data to another application.
when i write below code in my main(), this is what happens
//Code to initialize QT widgets and working fine.
try
{
boost::asio::io_service io_service;
server s(io_service, 8888); //8888 is a port no.
io_service.run(); // **Even after successfull creation it doesn't look for incoming data**
}
catch(std::exception& e)
{
std::cout << "Exception : " << e.what() << std::endl;
}
//rest of the code for qt widget, which will be blocked by io_service.
i have tried poll() as well to avoid this but it is also not wait for any incoming data.
is there any way to achieve both at a time??
Regards,
Jithendra.

io_service requires a thread of its own to not block other operations. also, instead of starting a thread on run(), there's an object called boost::asio::io_service::work that ensures run() is always executed, even when it returns.
here's how I usually implement io_service to run:
IoServiceWork.h:
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
class IoServiceWork
{
public:
IoServiceWork()
: m_ioService(new boost::asio::io_service()),
m_ioServiceWork(new boost::asio::io_service::work(*m_ioService)),
m_ioWorkThread(new boost::thread(boost::bind(&boost::asio::io_service::run, m_ioService)))
{
}
~IoServiceWork()
{
delete m_ioServiceWork;
m_ioWorkThread->join();
delete m_ioWorkThread;
delete m_ioService;
}
boost::asio::io_service& ioService()
{
return *m_ioService;
}
boost::asio::io_service* m_ioService;
boost::asio::io_service::work* m_ioServiceWork;
boost::thread* m_ioWorkThread;
};
Then I access my static global io_service object from any .cpp file from my project using this function.
CustomIOService.h:
#include <boost/asio.hpp>
boost::asio::io_service& IOService();
CustomIOService.cpp:
#include "IoServiceWork.h"
boost::asio::io_service& IOService()
{
static IoServiceWork ioServiceWork;
return ioServiceWork.ioService();
}
it is put as a static object in a function to avoid the static initialization order fiasco.
So, then, all you have to do to create your socket, or any object requiring an io_service object, such as server in your case:
#include <CustomIoService.h>
server s(IOService(), 8888);

Related

Boost asio handler that does not keep the io_service running

I want to add a signal handler to my boost io_service, allowing the application to shut down cleanly when the user presses Ctrl-C. This is of course easily done by stopping the loop, something like this:
boost::asio::io_service service;
boost::asio::signal_set signals{ service, SIGINT, SIGTERM };
signals.async_wait(std::bind(&boost::asio::io_service::stop, &service));
This stops the loop normally, allowing the destructors to do their routine clean-up behaviour.
The problem is, once the application runs out of work it does not stop because the signal handler still has a handler registered and thus the io_service never stops running.
I have not found a clean way around this. I could of course do the signal handling myself and then just stop the loop, but this kind of defeats the idea of using boost (portability).
In the following code, http_server has a "listening socket" to accept multiple connections. The listening socket constantly runs async_accept so the io_service never runs out of work. The http_server.shutdown() function closes the listening socket and all open connections, so the io_service has no more work and stops running:
void handle_stop(ASIO_ERROR_CODE const&, // error,
int, // signal_number,
http_server_type& http_server)
{
std::cout << "Shutting down" << std::endl;
http_server.shutdown();
}
...
ASIO::io_service io_service;
http_server_type http_server(io_service);
...
// The signal set is used to register termination notifications
ASIO::signal_set signals_(io_service);
signals_.add(SIGINT);
signals_.add(SIGTERM);
#if defined(SIGQUIT)
signals_.add(SIGQUIT);
#endif // #if defined(SIGQUIT)
// register the handle_stop callback
signals_.async_wait([&http_server]
(ASIO_ERROR_CODE const& error, int signal_number)
{ handle_stop(error, signal_number, http_server); });
...
io_service.run();
std::cout << "io_service.run complete, shutdown successful" << std::endl;
This method also works for thread pools, see:thread_pool_http_server.cpp
I am probably going to hell for this, but I found a workaround to get a handler that doesn't coun't towards the number of running handlers. It seriously abuses both the work_guard boost provides, calls destructors by hand and misuses placement new, but it works.
#pragma once
#include <boost/asio/io_service.hpp>
#include <utility>
#include <memory>
template <typename HANDLER>
class unwork
{
public:
unwork(boost::asio::io_service &service, HANDLER &&handler) :
_work_guard(std::make_unique<boost::asio::io_service::work>(service)),
_handler(std::forward<HANDLER>(handler))
{
// wait for the handler to be installed
service.post([work_guard = _work_guard.operator->()]() {
// remove the work guard and the handler that has now been installed
work_guard->~work();
work_guard->~work();
});
}
unwork(const unwork &that) :
unwork(that._work_guard->get_io_service(), that._handler)
{}
unwork(unwork &&that) :
_work_guard(std::move(that._work_guard)),
_handler(std::move(that._handler))
{}
~unwork()
{
// was the work guard not moved out?
if (_work_guard) {
// add the work guard reference and the handler reference again
new (_work_guard.operator->()) boost::asio::io_service::work{ _work_guard->get_io_service() };
new (_work_guard.operator->()) boost::asio::io_service::work{ _work_guard->get_io_service() };
}
}
template <class ...Arguments>
auto operator()(Arguments ...parameters)
{
return _handler(std::forward<Arguments>(parameters)...);
}
private:
std::unique_ptr<boost::asio::io_service::work> _work_guard;
HANDLER _handler;
};
// maker function, for c++ < c++17
template <typename HANDLER>
unwork<HANDLER> make_unwork(boost::asio::io_service &service, HANDLER &&handler)
{
// create the new unwork wrapper
return { service, std::forward<HANDLER>(handler) };
}
It is used by wrapping your handler in a make_unwork() call if you are using c++14. In c++17 the constructor can be used directly.

C++ Boost.Asio object lifetimes

asio::io_service ioService;
asio::ip::tcp::socket* socket = new asio::ip::tcp::socket(ioService);
socket->async_connect(endpoint, handler);
delete socket;
Socket's destructor should close the socket. But can the asynchronous backend handle this? Will it cancel the asynchronous operation and calling the handler? Probably not?
When the socket is destroyed, it invokes destroy on its service. When a SocketService's destroy() function is invoked, it cancels asynchronous operations by calling a non-throwing close(). Handlers for cancelled operations will be posted for invocation within io_service with a boost::asio::error::operation_aborted error.
Here is a complete example demonstrating the documented behavior:
#include <iostream>
#include <boost/asio.hpp>
void handle_connect(const boost::system::error_code& error)
{
std::cout << "handle_connect: " << error.message() << std::endl;
}
int main()
{
namespace ip = boost::asio::ip;
using ip::tcp;
boost::asio::io_service io_service;
// Create socket with a scoped life.
{
tcp::socket socket(io_service);
socket.async_connect(
tcp::endpoint(ip::address::from_string("1.2.3.4"), 12345),
&handle_connect);
}
io_service.run();
}
And its output:
handle_connect: Operation canceled
Why did you create the socket using new? It won't definitely do normal process.
If you really want to create the socket using new, you have to close and delete at the end of your program.
Here is a sample, just.
io_service service_;
ip::tcp::socket sock(service_);
sock.async_connect(ep, connect_handler);
deadline_timer t(service_, boost::posix_time::seconds(5));
t.async_wait(timeout_handler);
service_.run();

boost asio udp socket async_receive_from does not call the handler

I want to create an autonomous thread devoted only to receive data from an UDP socket using boost libraries (asio). This thread should be an infinite loop triggered by some data received from the UDP socket. In my application I need to use an asynchronous receive operation.
If I use the synchronous function receive_from everything works as expected.
However if I use async_receive_from the handler is never called. Since I use a semaphore to detect that some data have been received, the program locks and the loop is never triggered.
I have verified (with a network analyzer) that the sender device properly sends the data on the UDP socket.
I have isolated the problem in the following code.
#include <boost\array.hpp>
#include <boost\asio.hpp>
#include <boost\thread.hpp>
#include <boost\interprocess\sync\interprocess_semaphore.hpp>
#include <iostream>
typedef boost::interprocess::interprocess_semaphore Semaphore;
using namespace boost::asio::ip;
class ReceiveUDP
{
public:
boost::thread* m_pThread;
boost::asio::io_service m_io_service;
udp::endpoint m_local_endpoint;
udp::endpoint m_sender_endpoint;
udp::socket m_socket;
size_t m_read_bytes;
Semaphore m_receive_semaphore;
ReceiveUDP() :
m_socket(m_io_service),
m_local_endpoint(boost::asio::ip::address::from_string("192.168.0.254"), 11),
m_sender_endpoint(boost::asio::ip::address::from_string("192.168.0.11"), 5550),
m_receive_semaphore(0)
{
Start();
}
void Start()
{
m_pThread = new boost::thread(&ReceiveUDP::_ThreadFunction, this);
}
void _HandleReceiveFrom(
const boost::system::error_code& error,
size_t received_bytes)
{
m_receive_semaphore.post();
m_read_bytes = received_bytes;
}
void _ThreadFunction()
{
try
{
boost::array<char, 100> recv_buf;
m_socket.open(udp::v4());
m_socket.bind(m_local_endpoint);
m_io_service.run();
while (1)
{
#if 1 // THIS WORKS
m_read_bytes = m_socket.receive_from(
boost::asio::buffer(recv_buf), m_sender_endpoint);
#else // THIS DOESN'T WORK
m_socket.async_receive_from(
boost::asio::buffer(recv_buf),
m_sender_endpoint,
boost::bind(&ReceiveUDP::_HandleReceiveFrom, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
/* The program locks on this wait since _HandleReceiveFrom
is never called. */
m_receive_semaphore.wait();
#endif
std::cout.write(recv_buf.data(), m_read_bytes);
}
m_socket.close();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
};
void main()
{
ReceiveUDP receive_thread;
receive_thread.m_pThread->join();
}
A timed_wait on the semaphore is to be preferred, however for debug purposes I have used a blocking wait as in the code above.
Did I miss something? Where is my mistake?
Your call to io_service.run() is exiting because there is no work for the io_service to do. The code then enters the while loop and calls m_socket.async_receive_from. At this point the io_service is not running ergo it never reads the data and calls your handler.
you need to schedule the work to do before calling io_service run:
ie:
// Configure io service
ReceiveUDP receiver;
m_socket.open(udp::v4());
m_socket.bind(m_local_endpoint);
m_socket.async_receive_from(
boost::asio::buffer(recv_buf),
m_sender_endpoint,
boost::bind(&ReceiveUDP::_HandleReceiveFrom, receiver,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
The handler function will do the following:
// start the io service
void HandleReceiveFrom(
const boost::system::error_code& error,
size_t received_bytes)
{
m_receive_semaphore.post();
// schedule the next asynchronous read
m_socket.async_receive_from(
boost::asio::buffer(recv_buf),
m_sender_endpoint,
boost::bind(&ReceiveUDP::_HandleReceiveFrom, receiver,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
m_read_bytes = received_bytes;
}
Your thread then simply waits for the semaphore:
while (1)
{
m_receive_semaphore.wait();
std::cout.write(recv_buf.data(), m_read_bytes);
}
Notes:
Do you really need this additional thread? The handler is completely asynchronous, and boost::asio can be used to manage a thread pool (see: think-async)
Please do not use underscores followed by a capitol letter for variable / function names. They are reserved.
m_io_service.run() returns immediately, so noone dispatches completion handlers. Note that io_service::run is a kind of "message loop" of an asio-based application, and it should run as long as you want asio functionality to be available (this's a bit simplified description, but it's good enough for your case).
Besides, you should not invoke async.operation in a loop. Instead, issue subsequent async.operation in the completion handler of the previous one -- to ensure that 2 async.reads would not run simultaniously.
See asio examples to see the typical asio application design.

Boost::asio - how to interrupt a blocked tcp server thread?

I'm working on a multithreaded application in which one thread acts as a tcp server which receives commands from a client. The thread uses a Boost socket and acceptor to wait for a client to connect, receives a command from the client, passes the command to the rest of the application, then waits again. Here's the code:
void ServerThreadFunc()
{
using boost::asio::ip::tcp;
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port_no));
for (;;)
{
// listen for command connection
tcp::socket socket(io_service);
acceptor.accept(socket);
// connected; receive command
boost::array<char,256> msg_buf;
socket.receive(boost::asio::buffer(msg_buf));
// do something with received bytes here
}
}
This thread spends most of its time blocked on the call to acceptor.accept(). At the moment, the thread only gets terminated when the application exits. Unfortunately, this causes a crash after main() returns - I believe because the thread tries to access the app's logging singleton after the singleton has been destroyed. (It was like that when I got here, honest guv.)
How can I shut this thread down cleanly when it's time for the application to exit? I've read that a blocking accept() call on a raw socket can be interrupted by closing the socket from another thread, but this doesn't appear to work on a Boost socket. I've tried converting the server logic to asynchronous i/o using the Boost asynchronous tcp echo server example, but that just seems to exchange a blocking call to acceptor::accept() for a blocking call to io_service::run(), so I'm left with the same problem: a blocked call which I can't interrupt. Any ideas?
In short, there are two options:
Change code to be asynchronous (acceptor::async_accept() and async_read), run within the event loop via io_service::run(), and cancel via io_service::stop().
Force blocking calls to interrupt with lower level mechanics, such as signals.
I would recommend the first option, as it is more likely to be the portable and easier to maintain. The important concept to understand is that the io_service::run() only blocks as long as there is pending work. When io_service::stop() is invoked, it will try to cause all threads blocked on io_service::run() to return as soon as possible; it will not interrupt synchronous operations, such as acceptor::accept() and socket::receive(), even if the synchronous operations are invoked within the event loop. It is important to note that io_service::stop() is a non-blocking call, so synchronization with threads that were blocked on io_service::run() must use another mechanic, such as thread::join().
Here is an example that will run for 10 seconds and listens to port 8080:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <iostream>
void StartAccept( boost::asio::ip::tcp::acceptor& );
void ServerThreadFunc( boost::asio::io_service& io_service )
{
using boost::asio::ip::tcp;
tcp::acceptor acceptor( io_service, tcp::endpoint( tcp::v4(), 8080 ) );
// Add a job to start accepting connections.
StartAccept( acceptor );
// Process event loop.
io_service.run();
std::cout << "Server thread exiting." << std::endl;
}
void HandleAccept( const boost::system::error_code& error,
boost::shared_ptr< boost::asio::ip::tcp::socket > socket,
boost::asio::ip::tcp::acceptor& acceptor )
{
// If there was an error, then do not add any more jobs to the service.
if ( error )
{
std::cout << "Error accepting connection: " << error.message()
<< std::endl;
return;
}
// Otherwise, the socket is good to use.
std::cout << "Doing things with socket..." << std::endl;
// Perform async operations on the socket.
// Done using the socket, so start accepting another connection. This
// will add a job to the service, preventing io_service::run() from
// returning.
std::cout << "Done using socket, ready for another connection."
<< std::endl;
StartAccept( acceptor );
};
void StartAccept( boost::asio::ip::tcp::acceptor& acceptor )
{
using boost::asio::ip::tcp;
boost::shared_ptr< tcp::socket > socket(
new tcp::socket( acceptor.get_io_service() ) );
// Add an accept call to the service. This will prevent io_service::run()
// from returning.
std::cout << "Waiting on connection" << std::endl;
acceptor.async_accept( *socket,
boost::bind( HandleAccept,
boost::asio::placeholders::error,
socket,
boost::ref( acceptor ) ) );
}
int main()
{
using boost::asio::ip::tcp;
// Create io service.
boost::asio::io_service io_service;
// Create server thread that will start accepting connections.
boost::thread server_thread( ServerThreadFunc, boost::ref( io_service ) );
// Sleep for 10 seconds, then shutdown the server.
std::cout << "Stopping service in 10 seconds..." << std::endl;
boost::this_thread::sleep( boost::posix_time::seconds( 10 ) );
std::cout << "Stopping service now!" << std::endl;
// Stopping the io_service is a non-blocking call. The threads that are
// blocked on io_service::run() will try to return as soon as possible, but
// they may still be in the middle of a handler. Thus, perform a join on
// the server thread to guarantee a block occurs.
io_service.stop();
std::cout << "Waiting on server thread..." << std::endl;
server_thread.join();
std::cout << "Done waiting on server thread." << std::endl;
return 0;
}
While running, I opened two connections. Here is the output:
Stopping service in 10 seconds...
Waiting on connection
Doing things with socket...
Done using socket, ready for another connection.
Waiting on connection
Doing things with socket...
Done using socket, ready for another connection.
Waiting on connection
Stopping service now!
Waiting on server thread...
Server thread exiting.
Done waiting on server thread.
When you receive an event that it's time to exit, you can call acceptor.cancel(), which will cancel the pending accept (with an error code of operation_canceled). On some systems, you might also have to close() the acceptor as well to be safe.
If it comes to it, you could open a temporary client connection to it on localhost - that will wake it up. You could even send it a special message so that you can shut down your server from the pub - there should be an app for that:)
Simply call shutdown with native handle and the SHUT_RD option, to cancel the existing receive(accept) operation.
The accepted answer is not exactly correct. Infact #JohnYu answered correctly.
Using blocking API of ASIO is much like using BSD sockets API that ASIO library wraps in its classes.
Problem is boost::asio::ip::tcp::acceptor class does not provide shutdown() functionality so you must do it using "old" sockets API.
Additional note: Make sure acceptor, socket and io_service are not deleted before all threads using it exit. In following code std::shared_ptr is used to keep shared resources alive so user of ApplicationContext class can delete the ApplicationContext object and avoid SEGFAULT crash.
Additional note: pay attention to boost documentation, there are overloaded methods that raise exception and ones that return error code. Original Poster's code used acceptor->accept(socket); without try/catch which would cause program exit instead of normal thread-routine exit and cleanup.
Here is the solution description:
#include <unistd.h> // include ::shutdown() function
// other includes ...
using boost::asio::ip::tcp;
using boost::asio::io_service;
class ApplicationContext {
// Use shared pointer to extend life of resources afer ApplicationContext is deleted
// and running threads can still keep using shared resources
std::shared_ptr<tcp::acceptor> acceptor;
std::shared_ptr<io_service> ioservice;
// called `ServerThreadFunc` in question code example
void AcceptLoopThreadRoutine(int port_no) {
ioservice = std::make_shared<io_service>();
acceptor = std::make_shared<tcp::acceptor>(*ioservice, tcp::endpoint(tcp::v4(), port_no));
try {
for (;;) {
// listen for client connection
tcp::socket socket(*ioservice);
// Note boost::system::system_error is raised when using this overload
acceptor->accept(socket);
// connected receive some data ...
// // boost::array<char,256> msg_buf;
// // socket.receive(boost::asio::buffer(msg_buf));
// do something with received bytes here
}
} catch(std::exception const & exception) {
// boost::system::system_error here indicates clean exit ;)
}
}
void StopAcceptThread() {
if(acceptor) {
// boost::asio::ip::tcp::acceptor does not have shutdown() functionality
// exposed, so we need to do it with this low-level approach
int shutdown_status = shutdown(acceptor->native_handle(), SHUT_RDWR);
}
}
};
Also note that using signals to unblock accept thread is very nasty implementation and temporary client connection on localhost to unblock accept thread is very awkward.
The ASIO is here to help you accomplish everything in single thread with callbacks. If you are mixing threads and ASIO chances are your design is bad.
Additional note: Do not confuse shutdown() and close(). Some systems may allow you to use close() on accept socket to unblock accept loop but this is not portable.

Triggering writes with Boost::asio

I have some software that I would like to make a TCP client. I don't know if this is the best architecture, but in my software I spawn a thread that will be used for the Network I/O. If there is a better architecture, I'd appreciate some pointers and advice.
Both threads have a refernce to the boost::asio::io_service object and a Session object that encapsulates the socket object. The sesson object is roughly as follows:
class Session
{
public:
Session(
boost::asio::io_service & io_service,
std::string const & ip_address,
std::string const & port)
: io_service_(io_service),
resolver_(io_service),
socket_(io_service),
ip_address_(ip_address),
port_(port),
{}
virtual void start();
virtual ~Session();
virtual void stop();
void write(std::string const & msg);
void handle_resolve(
const boost::system::error_code & error,
boost::asio::ip::tcp::resolver::iterator endpoint_itr);
void handle_connect(
const boost::system::error_code & error,
boost::asio::ip::tcp::resolver::iterator endpoint_itr);
void handle_close();
void handle_write(const boost::system::error_code & error);
private:
boost::asio::io_service & io_service_;
boost::asio::ip::tcp::resolver resolver_;
boost::asio::ip::tcp::socket socket_;
std::string ip_address_;
std::string port_;
};
In the I/O thread run-loop, the start() method of the session object is called which connects to the server. (This works, btw). Then, the thread sits in a loop calling the run() method on the I/O service object [io_service_.run()] to trigger events.
The main thread calls the write() method of the session when it wants to send data, and the session object calls boost::async_write with the data to write and then a callback method that is a member of the session object (handle_write).
While I have the I/O thread connecting to the server, I cannot get the handle_write method to be triggered. I have verified that the main thread is calling into the session object and executing async_write() on the socket. It is just that the callback is never triggered. I also don't see any data on the server side or over the wire with tcpdump.
Any idea where my problem might be? Is there a better way to organize the architecture? Most of all, I don't want to block the main thread doing I/O.
Here is the code that spawns the io thread from the main thread (apologies for the spacing):
boost::asio::io_service io_service;
boost::shared_ptr<Session> session_ptr;
boost::thread io_thread;
....
session_ptr.reset(
new Session::Session(
io_service,
std::string("127.0.0.1"),
std::string("17001")));
// spawn new thread for the network I/O endpoint
io_thread = boost::thread(
boost::bind(
&Session::start,
session_ptr_.get()));
The code for the start() method is as follows:
void Session::start()
{
typedef boost::asio::ip::tcp tcp;
tcp::resolver::query query(
tcp::v4(),
ip_address_,
port_);
resolver_.async_resolve(
query,
boost::bind(
&Session::handle_resolve,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
while(1){ // improve this later
io_service_.run();
}
}
The callback for the resolver:
void Session::handle_resolve(
const boost::system::error_code & error,
boost::asio::ip::tcp::resolver::iterator endpoint_itr)
{
if (!error)
{
boost::asio::ip::tcp::endpoint endpoint = *endpoint_itr;
socket_.async_connect(
endpoint,
boost::bind(
&Session::handle_connect,
this,
boost::asio::placeholders::error,
++endpoint_itr));
}
else
{
std::cerr << "Failed to resolve\n";
std::cerr << "Error: " << error.message() << std::endl;
}
}
The callback for connect:
void Session::handle_connect(
const boost::system::error_code & error,
boost::asio::ip::tcp::resolver::iterator endpoint_itr)
{
typedef boost::asio::ip::tcp tcp;
if (!error)
{
std::cerr << "Connected to the server!\n";
}
else if (endpoint_itr != tcp::resolver::iterator())
{
socket_.close();
socket_.async_connect(
*endpoint_itr,
boost::bind(
&Session::handle_connect,
this,
boost::asio::placeholders::error,
++endpoint_itr));
}
else
{
std::cerr << "Failed to connect\n";
}
}
The write() method that the main thread can call to send post an asychronous write.
void Session::write(
std::string const & msg)
{
std::cout << "Write: " << msg << std::endl;
boost::asio::async_write(
socket_,
boost::asio::buffer(
msg.c_str(),
msg.length()),
boost::bind(
&Session::handle_write,
this,
boost::asio::placeholders::error));
}
And finally, the write completion callback:
void Session::handle_write(
const boost::system::error_code & error)
{
if (error)
{
std::cout << "Write complete with errors !!!\n";
}
else
{
std::cout << "Write complete with no errors\n";
}
}
Looks like your io service will run out of work after connect, after which you just call io_service::run again? It looks like run is being called in the while loop, however I can't see a call to reset anywhere. You need to call io::service::reset before you call run on the same io_service again.
Structurally, it would be better to add work to the io_service, then you don't need to call it in the loop and the run will exit once you call io_service::stop.
this portion of your code
boost::asio::io_service io_service;
boost::shared_ptr<Session> session_ptr;
boost::thread io_thread;
....
session_ptr.reset(
new Session::Session(
io_service,
std::string("127.0.0.1"),
std::string("17001")));
// spawn new thread for the network I/O endpoint
io_thread = boost::thread(
boost::bind(
&Session::start,
session_ptr_.get()));
is a red flag to me. Your io_service object is possibly going out of scope and causing strange behavior. An io_service is not copyable, so passing it to your Session as a non-const reference is probably not what you are hoping to achieve.
samm#macmini ~> grep -C 2 noncopyable /usr/include/boost/asio/io_service.hpp
#include <boost/asio/detail/epoll_reactor_fwd.hpp>
#include <boost/asio/detail/kqueue_reactor_fwd.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/select_reactor_fwd.hpp>
#include <boost/asio/detail/service_registry_fwd.hpp>
--
*/
class io_service
: private noncopyable
{
private:
--
/// Class used to uniquely identify a service.
class io_service::id
: private noncopyable
{
public:
--
/// Base class for all io_service services.
class io_service::service
: private noncopyable
{
public:
If you're basing your code off the HTTP client example, you should note the io_service is in scope all the time inside of main(). As Ralf pointed out, your io_service is also likely running out of work to do after the connect handler, which is why you've kludged it to invoke run() inside of a loop
while(1){ // improve this later
io_service_.run();
}
again, note that the HTTP client example does not do this. You need to start another async operation inside of the connect handler, either a read or write depending on what your application needs.