I used the async tcp server example from boost which is near to what my application is doing. The code example below is a fully working example.
At first I start an async read operation until the delimiter char. In this case it is the http header complete sequence. The request contains some payload which is "hello world" (11 bytes). For a simplified example I use lambda handlers here. The first handler is called wit a length of 148 which is the header including four bytes for the delimiter sequence.
The size of the buffer gives me 159 which is the whole request including the payload. So far everything works as expected. To receive the payload I call another async read operation but the handler is never called. The first I tried was to read 11 bytes but that didn't work so I tried to read just two bytes to check if it's working buts it isn't.
The streambuf already contains all the data but why is the async read handler not called. Shouldn't it be called immediately because the data is inside the buffer or is there any misuse of the api?
Edit1:
I ended up checking calculating the bytes to read with the bytes inside the buffer. When there is no need for a "true" read operation I use io_server::post to add a wrapper for the handler. This seems as the best option for that purpose.
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
public:
session(tcp::socket socket)
: socket_(std::move(socket))
{
}
boost::asio::streambuf buf;
void start()
{
do_read();
}
private:
void do_read()
{
auto self(shared_from_this());
boost::asio::async_read_until(socket_,buf, "\r\n\r\n", [this, self](boost::system::error_code ec, std::size_t length){
std::istream in(&buf);
std::cout << length << std::endl;
std::cout << buf.size() << std::endl;
in.ignore(length);
boost::asio::async_read(socket_, buf, boost::asio::transfer_exactly(2), [this, self](boost::system::error_code ec, std::size_t length){
std::istream in(&buf);
std::cout << length << std::endl;
});
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read();
}
});
}
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
socket_(io_service)
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec)
{
if (!ec)
{
std::make_shared<session>(std::move(socket_))->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: async_tcp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
server s(io_service, std::atoi(argv[1]));
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}