I am porting an application which uses Boost::Asio to an embedded system.
I have already cross-compiled boost 1.57.0 binaries for the board using its BSP. To test the libraries working, I ran two http server examples that use synchronized and asynchronized writing respectively.
The Sync version runs fine; while the Async one failed at writing. It returned error "Operation canceled".
Can anyone point out where I should look for? Thanks.
/*
* Boost::Asio async example
*/
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/smart_ptr.hpp>
using namespace boost::asio;
using boost::system::error_code;
using ip::tcp;
struct CHelloWorld_Service
{
CHelloWorld_Service(io_service &iosev)
:m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 1000))
{}
void start()
{
boost::shared_ptr<tcp::socket> psocket(new tcp::socket(m_iosev));
m_acceptor.async_accept(*psocket,
boost::bind(&CHelloWorld_Service::accept_handler, this, psocket, _1));
}
void accept_handler(boost::shared_ptr<tcp::socket> psocket, error_code ec)
{
if(ec) return;
start();
std::cout << psocket->remote_endpoint().address() << std::endl;
boost::shared_ptr<std::string> pstr(new std::string("hello async world!"));
psocket->async_write_some(buffer(*pstr),
boost::bind(&CHelloWorld_Service::write_handler, this, pstr, _1, _2));
}
void write_handler(boost::shared_ptr<std::string> pstr, error_code ec,
size_t bytes_transferred)
{
if(ec)
std::cout<< "Failed to send! " << boost::system::system_error(ec).what() << std::endl;
else
std::cout<< *pstr << " has been sent" << std::endl;
}
private:
io_service &m_iosev;
ip::tcp::acceptor m_acceptor;
};
int main(int argc, char* argv[])
{
io_service iosev;
CHelloWorld_Service sev(iosev);
sev.start();
iosev.run();
return 0;
}
On your
async_write_some
call you forget to hold a reference to the socket instance.This causes the
socket
object to be destructed, and as part of the destructor, all pending asynchronous operations are canceled. This explains that you receiveec
operation_aborted
.Fix it either by adding the
socket
pointer to the bound arguments, or alternatively use theenable_shared_from_this
idiom with yourCSession
type.Using more
shared_pointer
magic:Here's the "simplest" edit:
Which should be bound like:
Live On Coliru
Several style improvements
using namespace
asio
placeholders (not_1
,_2
)Prints:
Using
CSession
(enable_shared_from_this)This is the other idiom, and it avoid spelling out all the shared-pointers.
Instead of keeping spearate shared pointers to the socket and buffer, you make a class to contain both:
And now the bind looks like:
Much simpler. Session management is the responsibility of the
CService
, like before:Again Live On Coliru
With similar output.