boost::asio::async_read does not callback my handler function

1.5k views Asked by At

I am working with boost::asio for TCP communication between a client & server app both of which are written by me. I'd initially written this with synchronous data reading that is using boost::asio::read. The sync_read is working all fine except that I am unable to so do a socket.cancel during a read operation. This has become quite a constraint & hence I am now trying convert my synchronous read to do async_read mechanism.

Following was my synchronous read mechanism which really well. I do 2 reads. Firstly get the packet header then get the packet data which works pretty well ->

size_t Read_Data_Sync(std::vector<unsigned char> & msg_body) {
  //fetch the header
  MyMessageHeader msg_header;
  boost::system::error_code err_code;
  size_t bytes_received = boost::asio::read(socket, boost::asio::buffer(&msg_header, sizeof(msg_header)), err_code);

  if (bytes_received <= 0 || err_code)
    return 0;

  err_code.clear();
  msg_body.resize(msg_header.size);

  //fetch the body
  bytes_received = boost::asio::read(socket, boost::asio::buffer(msg_body), err_code);
  if (bytes_received <= 0 || error_code)
    return 0;

  return bytes_received;
}

Above function used to get called continuously from a thread on the client side which I call it a reader thread like so ->

auto data_reader_thread = std::thread {[this] {
    while(run_thread) {
        Read_Data_Sync();
    }
}};

Following is how I am changing this to make the read mechanism async ->

The reader thread stays that same except that it now calls another read function which I have coded to do read data in an async way

auto data_reader_thread = std::thread {[this] {
    while(run_thread) {
        Read_Data_Async();
    }
}};

I have made the msg_body & msg_header as member variables in my class. The renewed logic is that Read_Data_Async is called from thread function continuously. Read_Data_Async calls boost::asio::async_read binding the address of Handle_Read_Header as callback which in turn again does a boost::asio::async_read to read the message body passing a handler callback to receive message_body

void Read_Data_Async() 
{
    //firstly read message header
    MyMessageHeader msg_header;
    boost::asio::async_read(socket, boost::asio::buffer(&msg_header, sizeof(msg_header)), boost::bind(&TCPSession::Handle_Read_Header, this,
                                                                                                             boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Handle_Read_Header(const boost::system::error_code & error, std::size_t bytes_transferred)
{
    //now read the message body
    if (!error && bytes_transferred > 0) {
        boost::asio::async_read(socket, boost::asio::buffer(msg_body), boost::bind(&TCPSession::Handle_Read_Body, this,
                                                                                                                 boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
    else {
        cout << "Error: " << error << "\n";
    }
}


void Handle_Read_Body(const boost::system::error_code & error, std::size_t bytes_transferred)
{
    if (!error && bytes_transferred > 0) {
        // msg_body has the data read from socket
    }
    else if (error != boost::asio::error::eof) {
        cout << "Error: " << error << "\n";
    }
}

The problem I am facing now is that the callback Handle_Read_Header never gets called back !! What is wrong with what I doing ? I looked through quite a few related posts like this one trying to resolve my problem but again that link is suggesting to call io.run because its about boost::asio::async_read_until not boost::asio::async_read.

Is my above logic correct wrt to boost::asio::async_read ? What should I get asio to call back my handler function ?

1

There are 1 answers

6
sehe On

You must run io_service::run() somewhere ¹

Actually, the whole idea of doing asynchronous IO is that you do NOT need the separate threads for reading/writing: full duplex is entirely possible on a single thread.


¹ or some more complicated loop with run_one, poll or poll_one