I have the two following functions for sending and receiving packets.
void send(std::string protocol)
char *request=new char[protocol.size()+1];
request[protocol.size()] = 0;
request_length = std::strlen(request);
boost::asio::write(s, boost::asio::buffer(request, request_length));
size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
std::cout << "Reply is: ";
std::cout << "\n";
To get the size of a buffer, the
boost::asio::buffer_size() function can be used. However, in your example, this will most likely be of little use to you.
As explained in the buffer overview, Boost.Asio use buffer classes to represent buffers. These classes provide an abstraction and protect Boost.Asio operations against buffer overruns. Although the result of
boost::asio::buffer() is passed to operations, the meta-data, such as the size of the buffer or its underlying type, is not transmitted. Also, these buffers do not own the memory, so it is the applications responsibility to ensure the underlying memory remains valid throughout the duration of the buffer abstraction's lifetime.
boost::asio::buffer() function provides a convenient way to create the buffer classes, where the size of the buffer is deduced from the type possible. When Boost.Asio is able to deduce the buffer length, then Boost.Asio operations will not invoke a buffer overflow when using the resulting buffer type. However, if the application code specifies the size of the buffer to
boost::asio::buffer(), then it is the applications responsibility to ensure that the size is not larger than the underlying memory.
When reading data, a buffer is required. The fundamental question becomes how does one know how much memory to allocate, if Boost.Asio does not transmit the size. There are a few solutions to this problem:
Query the socket for how much data is available via
socket::available(), then allocate the buffer accordingly.
std::vector<char> data(socket_.available()); boost::asio::read(socket_, boost::asio::buffer(data));
Use a class that Boost.Asio can grow in memory, such as
boost::asio::streambuf. Some operations, such as
streambuf objects as their buffer and will allocate memory as is required for the operation. However, a completion condition should be provided; otherwise, the operation will continue until the buffer is full.
boost::asio::streambuf data; boost::asio::read(socket_, data, boost::asio::transfer_at_least(socket_.available()));
As Öö Tiib suggests, incorporate length as part of the communication protocol. Check the Boost.Asio examples for examples of communication protocols. Focus on the protocol, not necessarily on the Boost.Asio API.
In a variable length protocol, the messages are often divided into two parts: a header and a body. The header is normally fixed size, and can contain various meta-information, such as the length of the body. This allows a reader to read a header into a fixed size buffer, extract the body length, allocate a buffer for the body, then read the body.
// Read fixed header. std::vector<char> data(fixed_header_size); boost::asio::read(socket_, boost::asio::buffer(data)); protocol::header header(data); network_to_local(header); // Handle endianess. // Read body. data.resize(header.body_length()); boost::asio::read(socket_, boost::asio::buffer(data)); protocol::body body(data); network_to_local(body); // Handle endianess.