Boost::Asio Async write failed

kc2

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;
}
sehe

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 receive ec operation_aborted.

Fix it either by adding the socket pointer to the bound arguments, or alternatively use the enable_shared_from_this idiom with your CSession type.

Using more shared_pointer magic:

Here's the "simplest" edit:

void write_handler(
        boost::shared_ptr<std::string> pstr, 
        boost::shared_ptr<tcp::socket> /*keepalive!*/, 
        error_code ec, size_t bytes_transferred) 
{
    if(ec)
        std::cout<< "Failed to send! " << boost::system::system_error(ec).what() << "\n";
    else
        std::cout<< *pstr << " has been sent (" << bytes_transferred << " bytes transferred)\n";
}

Which should be bound like:

    psocket->async_write_some(ba::buffer(*pstr),
            boost::bind(&CService::write_handler, this, pstr, psocket,
                ba::placeholders::error, ba::placeholders::bytes_transferred));

Live On Coliru

Several style improvements

  • not using namespace
  • using the asio placeholders (not _1, _2)

Prints:

g++ -std=c++11 -O2 -Wall -pedantic main.cpp -pthread -lboost_system -lboost_filesystem && ./a.out& while sleep .1; do nc 127.0.0.1 6767; done
127.0.0.1
hello async world!hello async world! has been sent (18 bytes transferred)
127.0.0.1
hello async world!hello async world! has been sent (18 bytes transferred)
127.0.0.1
hello async world!hello async world! has been sent (18 bytes transferred)
...

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:

struct CSession : boost::enable_shared_from_this<CSession> {
    CSession(ba::io_service &iosev)
        :m_iosev(iosev), m_sock(m_iosev)
    {}

    void do_response();

  private:
    void write_handler(error_code ec, size_t bytes_transferred);

    ba::io_service &m_iosev;
    tcp::socket m_sock;
    std::string response;
};

And now the bind looks like:

boost::bind(&CSession::write_handler,
     shared_from_this(), /* keep-alive! */
     ba::placeholders::error, ba::placeholders::bytes_transferred)

Much simpler. Session management is the responsibility of the CService, like before:

void start()
{
    auto session = boost::make_shared<CSession>(m_iosev);
    m_acceptor.async_accept(session->m_sock,
            boost::bind(&CService::accept_handler, this, session, ba::placeholders::error));
}

void accept_handler(boost::shared_ptr<CSession> session, error_code ec) {
    if(ec) {
        std::cerr << "Accept failed: " << ec.message() << "\n";
    } else {
        session->do_response();
        start();
    }
}

Again Live On Coliru

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>

namespace ba = boost::asio;
using boost::system::error_code;
using ba::ip::tcp;

namespace HelloWorld {

    struct CSession : boost::enable_shared_from_this<CSession> {
        CSession(ba::io_service &iosev)
            :m_iosev(iosev), m_sock(m_iosev)
        {}

        void do_response() {
            response = "hello async world!\n";
            std::cout << m_sock.remote_endpoint().address() << std::endl;

            m_sock.async_write_some(ba::buffer(response),
                    boost::bind(&CSession::write_handler,
                        shared_from_this(), /* keep-alive! */
                        ba::placeholders::error, ba::placeholders::bytes_transferred));
        }

      private:

        void write_handler(error_code ec, size_t bytes_transferred) 
        {
            if(ec)
                std::cout<< "Failed to send! " << boost::system::system_error(ec).what() << "\n";
            else
                std::cout<< response << " has been sent (" << bytes_transferred << " bytes transferred)\n";
        }

        ba::io_service &m_iosev;

        friend class CService;
        tcp::socket m_sock;

        std::string response;
    };

    struct CService
    {
        CService(ba::io_service &iosev)
            :m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 6767))
        {}

        void start() {
            auto session = boost::make_shared<CSession>(m_iosev);
            m_acceptor.async_accept(session->m_sock,
                    boost::bind(&CService::accept_handler, this, session, ba::placeholders::error));
        }

        void accept_handler(boost::shared_ptr<CSession> session, error_code ec) {
            if(ec) {
                std::cerr << "Accept failed: " << ec.message() << "\n";
            } else {
                session->do_response();
                start();
            }
        }

      private:
        ba::io_service &m_iosev;
        tcp::acceptor m_acceptor;
    };
}

int main() {
    ba::io_service iosev;

    using namespace HelloWorld;

    CService sev(iosev);
    sev.start();
    iosev.run();
}

With similar output.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Boost::asio async_write_some vs async_send

From Dev

boost::asio::async_write and buffers over 65536 bytes

From Dev

What is the use of boost::asio::async_write function

From Dev

Boost ASIO - What is async

From Dev

Boost::Asio write lock

From Dev

How should I use async_read_until and async_write simultaneously in the client app in boost::asio?

From Dev

Boost Asio incomplete write to socket

From Dev

boost::asio read/write trouble

From Dev

Boost asio asynchronous read and then write

From Dev

boost::asio write: Broken pipe

From Dev

Boost asio TCP async server not async?

From Dev

boost asio async_write with shared buffer over multi-thread

From Dev

asio::async_write and strand

From Dev

boost asio async udp server - poor performance

From Dev

Generic way to timeout async operations in boost::asio

From Dev

Boost.Asio: Async operations timeout

From Dev

Boost asio trouble with async_read_until

From Dev

Boost asio async operation bad file descriptor

From Dev

boost asio async udp server - poor performance

From Dev

Boost.Asio: Async operations timeout

From Dev

Initializing boost::asio socket after constructor failed

From Dev

boost asio cancelling read without cancelling write

From Dev

What means blocking for boost::asio::write?

From Dev

Boost ASIO Serial Write Hex values

From Dev

boost asio cancelling read without cancelling write

From Dev

Boost ASIO Serial Write Hex values

From Dev

WriteHandler from boost::asio::async_write doesn't work properly when connection is dropped (firewall / manual disconecting the network)

From Dev

asio::async_write SEG FAULT

From Dev

Boost asio async_read_until followed by async_read

Related Related

HotTag

Archive