Abanoub
Abanoub

Reputation: 3809

Get number of bytes read by boost::asio::async_read

I am attempting to convert the return value of the function boost::asio::async_read to an int in order to see if I've received any data:

int recvlen = boost::asio::async_read (
    socket_,
    boost::asio::buffer((char*)buffer, 1000),
    boost::bind(&Connection::Receive, this, boost::asio::placeholders::error)
);

Here is that statement in the context of the rest of my code, which does not compile:

.h file:

#ifndef _CONNECTION_H_
#define _CONNECTION_H_

#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <stdint.h>

class Connection 
{
public:
    Connection(boost::asio::io_service& io_service);
    ~Connection();
    boost::asio::ip::tcp::socket& socket() {return socket_;}
    void Send(uint8_t* buffer, int length);
    bool Receive();

protected:
    virtual void OnReceived(uint8_t* buffer, int len) = 0;

private:
    boost::asio::ip::tcp::socket socket_;
};

#endif

.cpp file:

#include "Connection.h"

Connection::Connection(boost::asio::io_service& io_service)    
    : socket_(io_service) {}

Connection::~Connection() {}

void Connection::Send(uint8_t* buffer,int length) {
    boost::asio::async_write (
        socket_,
        boost::asio::buffer(buffer, length),
        boost::bind(&Connection::Send, this,boost::asio::placeholders::error)
    );
}

bool Connection::Receive(){
    uint8_t* buffer = new uint8_t[1000];

    //Conversion excerpt
    int recvlen = boost::asio::async_read (
        socket_,
        boost::asio::buffer((char*)buffer, 1000),
        boost::bind(&Connection::Receive, this, boost::asio::placeholders::error)
    );

    if (recvlen <= 0) {
        delete[] buffer;
        return false;
    }

    this->OnReceived(buffer, recvlen);

    delete[] buffer;

    return true;
}

These are the errors this code produces in Visual C++:

error C2825: 'F': must be a class or namespace when followed by '::'    e:\boost_1_46_1\boost_1_46_1\boost\bind\bind.hpp    69
error C2039: 'result_type' : is not a member of '`global namespace''    e:\boost_1_46_1\boost_1_46_1\boost\bind\bind.hpp    69
error C2146: syntax error : missing ';' before identifier 'type'    e:\boost_1_46_1\boost_1_46_1\boost\bind\bind.hpp    69
error C2208: 'boost::_bi::type' : no members defined using this type    e:\boost_1_46_1\boost_1_46_1\boost\bind\bind.hpp    69
error C1903: unable to recover from previous error(s); stopping compilation e:\boost_1_46_1\boost_1_46_1\boost\bind\bind.hpp    69
IntelliSense: a value of type "void" cannot be used to initialize an entity of type "int"   d:\c++\ugs\common\connection.cpp    18
IntelliSense: the #endif for this directive is missing  d:\c++\ugs\common\connection.h  1
IntelliSense: this declaration has no storage class or type specifier   d:\c++\ugs\common\connection.h  26

How can I accomplish what I'm trying to do? In addition, what do these errors mean and how can I fix them?

Upvotes: 4

Views: 4798

Answers (1)

Dan
Dan

Reputation: 3635

async_read does not return the number of bytes read. It performs the read in the background, asynchronously. The number of bytes is passed to the completion handler. The completion handler is invoked by ASIO when the read completes. You pass the completion handler into async_read. async_read is a template that accepts any function object as the handler. In your case, you passed the output of the bind statement.

There are good examples in the boost documentation, but here are two quick solutions.

You could use the synchronous boost::asio::read function instead of boost::asio::async_read.

int recvlen = boost::asio::read(socket_,boost::asio::buffer((char*)buffer, 1000));

Or, you could add a new function:

void HandleReceive(boost::system::error_code &error, std::size_t recvlen)
{
    if (!error && error != boost::asio::error::message_length) {
       this->OnReceived(buffer, recvlen);
       delete [] buffer;
    } // else ERROR!!!
}

And call async_read like

boost::asio::async_read(socket_,boost::asio::buffer((char*)buffer, 1000),
          boost::bind(&Connection::HandleReceive, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));

You will have to make buffer a class variable for the asynchronous example to work, but you may want to come up with a better way to manage the memory. Also, you will have to do something to deal with lifetime issues of the Connection class. Check the ASIO examples for a better developed example.

Upvotes: 3

Related Questions