Reputation: 3837
I just started working with the Boost ASIO library, version 1.52.0. I am using TCP/SSL encryption with async sockets. From other questions asked here about ASIO, it seems that ASIO does not support receiving a variable length message and then passing the data for that message to a handler.
I'm guessing that ASIO puts the data into a cyclical buffer and loses all track of each separate message. If I have missed something and ASIO does provide a way to pass individual messages, then please advise as to how.
My question is that assuming I can't somehow obtain just the bytes associated with an individual message, can I use transfer_exactly in async_read to obtain just the first 4 bytes, which our protocol always places the length of the message. Then call either read or async_read (if read won't work with async sockets) to read in the rest of the message? Will this work? Any better ways to do it?
Upvotes: 3
Views: 4799
Reputation: 1321
Typically I like to take the data I receive in an async_read and put it in a boost::circular_buffer and then let my message parser layer decide when a message is complete and pull the data out. http://www.boost.org/doc/libs/1_52_0/libs/circular_buffer/doc/circular_buffer.html
Partial code snippets below
boost::circular_buffer TCPSessionThread::m_CircularBuffer(BUFFSIZE);
void TCPSessionThread::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred)
{
// ignore aborts - they are a result of our actions like stopping
if (e == boost::asio::error::operation_aborted)
return;
if (e == boost::asio::error::eof)
{
m_SerialPort.close();
m_IoService.stop();
return;
}
// if there is not room in the circular buffer to hold the new data then warn of overflow error
if (m_CircularBuffer.reserve() < bytes)
{
ERROR_OCCURRED("Buffer Overflow");
m_CircularBuffer.clear();
}
// now place the new data in the circular buffer (overwrite old data if needed)
// note: that if data copying is too expensive you could read directly into
// the circular buffer with a little extra effor
m_CircularBuffer.insert(m_CircularBuffer.end(), pData, pData + bytes);
boost::shared_ptr<MessageParser> pParser = m_pParser.lock(); // lock the weak pointer
if ((pParser) && (bytes_transferred))
pParser->HandleInboundPacket(m_CircularBuffer); // takes a reference so that the parser can consume data from the circ buf
// start the next read
m_Socket.async_read_some(boost::asio::buffer(*m_pBuffer), boost::bind(&TCPSessionThread::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
Upvotes: 4