1

So,

I've been playing around with the Boost asio functions and sockets (specifically the async read/write). Now, I thought that boost::asio::async_read only called the handler when a new buffer came in from the network connection... however it doesn't stop reading the same buffer and thus keeps calling the handler. I've been able to mitigate it by checking the number of bytes transferred, however it is basically in a busy-waiting loop wasting CPU cycles.

Here is what I have:

class tcp_connection : : public boost::enable_shared_from_this<tcp_connection> 
{
public:
    // other functions here

    void start()
    {
    boost::asio::async_read(socket_, boost::asio::buffer(buf, TERRAINPACKETSIZE),
        boost::bind(&tcp_connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
    }

private:
    const unsigned int TERRAINPACKETSIZE = 128;
    char buf[TERRAINPACKETSIZE];


    void handle_read(const boost::system::error_code& error, size_t bytesT)
    {
        if (bytesT > 0)
        { 
             // Do the packet handling stuff here
        }

        boost::asio::async_read(socket_, boost::asio::buffer(buf, TERRAINPACKETSIZE),
        boost::bind(&tcp_connection::handle_read, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
    }
};

Some stuff is cut out, but basically a new connection gets created then start() is called. Is there something I'm missing so that the handle_read method doesn't get continuously called?

DigitalZebra
  • 39,494
  • 39
  • 114
  • 146
  • 1
    Could you show us how "buf" is initialized (and what is TERRAINPACKETSIZE)? I'm asking because I wonder if you could be in the same situation than the one discussed at: http://lists.boost.org/boost-users/2009/06/49370.php – Éric Malenfant Oct 29 '09 at 12:55
  • Eric, buf is a character array and TERRAINPACKETSIZE is a const holding the size of the buffer – DigitalZebra Oct 30 '09 at 16:29
  • 1
    I'm sorry, I'm nearly out of ideas to help you :( I took the "asynchronous echo tcp server" example from the asio docs and modified it so that its session does the same than the one you show here (plus checking on !error in handle_read) and it works fine. I tried that on Windows; on what platform are you running this? – Éric Malenfant Oct 30 '09 at 19:11
  • No worries man :). I'm running it on Windows, I found that if you call async_write then call async_read again it doesn't go into the loop. – DigitalZebra Oct 30 '09 at 23:39

2 Answers2

6

A wild guess: Do you check error in handle_read? If the socket is in an error state for some reason, I guess that the nested call to async_read made from handle_read will immediately "complete", resulting in an immediate call to handle_read

Éric Malenfant
  • 13,938
  • 1
  • 40
  • 42
  • You should only schedule another async_read if there is no error condition (if (!error) ...). – Dan Oct 29 '09 at 12:40
0

I was having the same problem. In my case, I was reading into a std::vector<unsigned_char> like this:

boost::asio::async_read(socket_,
st::asio::buffer(*message,message->size()),
            boost::bind(
              &ActiveSocketServerSession::handleFixLengthRead,
              shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred)
    );

I have an adaptative vector for accept a variant number of bytes

    std::vector<unsigned char>* message;
message = new std::vector<unsigned char> (sizePacket);

When I was receiving the first packet all was going fine, but after the first, never stops unlocking handle_reader with no data.

My solution was to delete my vector and alloc space again after processing it:

void ActiveSocketServerSession::handleFixLengthRead(    const         boost::system::error_code& error,
                                                    std::size_t bytes_transferred){

    --> processing your data (save to another site)
--> delete message;
--> message = new std::vector<unsigned char> (sizePacket);

//starting to read again
boost::asio::async_read(socket_,
                boost::asio::buffer(*message,message->size()),
            boost::bind(
              &ActiveSocketServerSession::handleFixLengthRead,
              shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred)
);

    }else{
        logMessage.str("");
        logMessage << "Error handling data id: "<<getId()<< "from port";
    }
}

After putting these two lines all goes fine.

lenz
  • 2,193
  • 17
  • 31
opernas
  • 154
  • 1
  • 10