Asio read queue

I needed to asynchronously read n bytes from the tcp stream in asio, but I couldn't find any appropriate api, so I made my own solution that uses a byte array as a queue for incoming data.
Here's the core of it.
What are you thoughts on it?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 // header file

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

class T : public boost::enable_shared_from_this<T>
{
...
private:
typedef void (T::*read_callback)(uint8_t*);

inline void ReadNBytes(size_t requested, read_callback handler);
void HandleReadNBytesPart(size_t requested, read_callback handler,
	const boost::system::error_code& ec, size_t bytes_transferred);

boost::array<uint8_t,1024> buf; // used as a queue
size_t bufStart;
size_t bufSize;
#define bufEnd (bufStart + bufSize)
#define bufStartPtr (buf.data() + bufStart)
#define bufEndPtr (buf.data() + bufEnd)
#define bufSpace (buf.size() - bufEnd)
...
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 // source file

void T::ReadNBytes(size_t requested, read_callback handler)
{
	// if we don't have the requested data
	if (bufSize < requested)
	{
		if (bufStart > 0) // if start isn't at the real start
		{
			// move data to the start (if there is any left from before)
			for (size_t i = 0; i < bufSize; ++i)
				buf[i] = buf[i + bufStart];
			bufStart = 0; // reset start
		}

		 // read data and write it at the end of the queue
		socket.async_receive(
			boost::asio::buffer(bufEndPtr, bufSpace),
			boost::bind(T::HandleReadNBytesPart, shared_from_this(),
				requested, handler,
				boost::asio::placeholders::error,
				boost::asio::placeholders::bytes_transferred));
	}
	else { // if we do have the requested data then call the callback
		uint8_t* startPtr = bufStartPtr;
		bufStart += requested;
		bufSize -= requested;

		(this->*handler)(startPtr); // maybe pass the same requested length number to the handler as well?
	}
}

void T::HandleReadNBytesPart(size_t requested, read_callback handler,
	const boost::system::error_code& ec, size_t bytes_transferred)
{
	if (ec)
	{
		HandleError("ReadNBytesPart", ec);
	}
	else {
		bufSize += bytes_transferred;

		ReadNBytes(requested, handler);
	}
}
Last edited on
> I needed to asynchronously read n bytes from the tcp stream in asio, but I couldn't find any appropriate api

See: http://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio/reference.html#boost_asio.reference.AsyncReadStream

I'm guessing you're trying to say that I should use a.async_read_some(mb, h); member of the socket
but I've already looked at the docs for basic_stream_socket::async_read_some and basic_stream_socket::async_receive and they both state

Remarks: The read operation may not read all of the requested number of bytes. Consider using the async_read function if you need to ensure that the requested amount of data is read before the asynchronous operation completes.

But when I tried using the async_read function I've discovered that if the buffer cannot hold the bytes received the data is simply disregarded meaning that next read doesn't get it, which broke my application.

Also a big advantage of my code here is that it will (if the data was previously received) call the handler in the same thread, like dispach() does, instead of doing it via post() like async_receive() and async_read_some() do, which is great for my use case since I have to read a few bytes at the time and can't know the length in advance.
zoran404 wrote:
when I tried using the async_read function I've discovered that if the buffer cannot hold the bytes received the data is simply disregarded meaning that next read doesn't get it, which broke my application.

That's not what I and other users of async_read observe. The next async_read gets the next byte. Or are you saying you somehow told async_read that your buffer holds more bytes than it actually does, such as by passing the wrong value to asio::buffer constructor?
Last edited on
That may be the case. I haven't had much experience with the api at the time.
Topic archived. No new replies allowed.