Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost.Asio async_send question

Tags:

c++

boost-asio

I'm using Boost.Asio for a server application that I'm writing.

async_send requires the caller to keep ownership of the data that is being sent until the data is sent successfully. That means my code (which looks like the following) will fail, and it does, because data will no longer be a valid object.

void func()
{
    std::vector<unsigned char> data;

    // ...
    // fill data with stuff
    // ...

    socket.async_send(boost::asio::buffer(data), handler);
}

So my solution was to do something like this:

std::vector<unsigned char> data;

void func()
{        
    // ...
    // fill data with stuff
    // ...

    socket.async_send(boost::asio::buffer(data), handler)
}

But now I'm wondering if I have multiple clients, will I need to create a separate vector for each connection?

Or can I use that one single vector? If I'm able to use that single vector, if I overwrite the contents inside it will that mess up the data I'm sending to all my clients?

like image 969
Marlon Avatar asked Mar 17 '11 20:03

Marlon


2 Answers

A possible fix would be to use a shared_ptr to hold your local vector and change the handler's signature to receive a shared_ptr so to prolong the life of the data until the sending is complete (thanks to Tim for pointing that out to me):

void handler( boost::shared_ptr<std::vector<char> > data )
{
}

void func()
{
    boost::shared_ptr<std::vector<char> > data(new std::vector<char>);
    // ...
    // fill data with stuff
    // ...

    socket.async_send(boost::asio::buffer(*data), boost:bind(handler,data));
}
like image 128
Eugen Constantin Dinca Avatar answered Sep 23 '22 12:09

Eugen Constantin Dinca


I solved a similar problem by passing a shared_ptr to my data to the handler function. Since asio holds on to the handler functor until it's called, and the hander functor keeps the shared_ptr reference, the data stays allocated as long as there's an open request on it.

edit - here's some code:

Here the connection object holds on to the current data buffer being written, so the shared_ptr is to the connection object, and the bind call attaches the method functor to the object reference and the asio call keeps the object alive.

The key is that each handler must start a new asyc operation with another reference or the connection will be closed. Once the connection is done, or an error occurrs, we simply stop generating new read/write requests. One caveat is that you need to make sure you check the error object on all your callbacks.

boost::asio::async_write(
    mSocket,
    buffers,
    mHandlerStrand.wrap(
        boost::bind(
            &TCPConnection::InternalHandleAsyncWrite,
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred)));

void TCPConnection::InternalHandleAsyncWrite(
    const boost::system::error_code& e,
    std::size_t bytes_transferred)
{
like image 37
Tim Sylvester Avatar answered Sep 22 '22 12:09

Tim Sylvester