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 ?
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