boost::asio:: buffer: получение размера буфера и предотвращение переполнения буфера?
у меня есть две следующие функции для отправки и получения пакетов.
void send(std::string protocol)
{
char *request=new char[protocol.size()+1];
request[protocol.size()] = 0;
memcpy(request,protocol.c_str(),protocol.size());
request_length = std::strlen(request);
boost::asio::write(s, boost::asio::buffer(request, request_length));
}
void receive()
{
char reply[max_length];
size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
std::cout << "Reply is: ";
std::cout.write(reply, reply_length);
std::cout << "n";
}
вопросы относятся к этой части boost::asio::buffer(reply, request_length)
где длина запроса-это длина строки, которая была изначально настроена при отправке пакета. Как проверить размер буфера, не зная request_length
? Другой вопрос: как предотвратить переполнение буфера?
3 ответов
чтобы получить размер буфера,boost::asio::buffer_size()
функцию можно использовать. Однако в вашем примере это, скорее всего, будет мало полезно для вас.
как объяснено в буфере обзор, импульс.Asio использует классы буферов для представления буферов. Эти классы обеспечивают абстракцию и защищают Boost.Операции Asio против переполнения буфера. Хотя результат boost::asio::buffer()
передается в операции, метаданные, такие как размер буфера или его базовый тип, не передается. Кроме того, эти буферы не владеют памятью, поэтому приложения несут ответственность за то, чтобы базовая память оставалась действительной в течение всего срока службы абстракции буфера.
на boost::asio::buffer()
функция предоставляет удобный способ создания классов буфера, где размер буфера выводится из возможного типа. Когда Импульс.Asio может вывести длину буфера, а затем увеличить.Операции Asio не будут вызывать переполнение буфера при использовании результирующего типа буфера. Однако, если код приложения указывает размер буфера на boost::asio::buffer()
, то это ответственность приложений, чтобы убедиться, что размер не больше, чем базовая память.
при чтении данных требуется буфер. Основной вопрос заключается в том, как узнать, сколько памяти выделить, если увеличить.Asio не передает размер. Есть несколько решений этого проблема:
-
запрос-розетка, сколько данных доступно через
socket::available()
, затем выделите буфер соответствующим образом.std::vector<char> data(socket_.available()); boost::asio::read(socket_, boost::asio::buffer(data));
-
используйте класс, который повышает.Asio может расти в памяти, например
boost::asio::streambuf
. Некоторые операции, такие какboost::asio::read()
приниматьstreambuf
объекты в качестве буфера и будут выделять память, необходимую для операции. Однако условием завершения должно быть при условии, в противном случае, операция будет продолжаться до тех пор, пока буфер не будет заполнен.boost::asio::streambuf data; boost::asio::read(socket_, data, boost::asio::transfer_at_least(socket_.available()));
-
As Öö Tiib предлагает включить длину как часть протокола связи. Проверь ускорение.Asio примеры для примеров протоколов связи. Сосредоточьтесь на протоколе, не обязательно на ускорении.Asio API.
- в протоколе фиксированного размера как производитель данных, так и потребитель используют одно и то же размер сообщения. Поскольку читатель знает размер сообщения, он может заранее выделить буфер.
-
в протоколе переменной длины сообщения часто делятся на две части: заголовок и тело. Заголовок обычно имеет фиксированный размер и может содержать различную метаинформацию, такую как длина тела. Это позволяет читателю прочитать заголовок в буфер фиксированного размера, извлечь длину тела, выделить буфер для тела, а затем прочитать тело.
// 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.
обычно протокол связи использует сообщения фиксированной длины или сообщения, содержащие заголовок, который сообщает длину сообщения.
импульс.ASIO online documentation содержит большой набор примеров и учебников, поэтому вы должны, возможно, начать оттуда. Википедия-хороший источник для объяснения передача данных терминология, boost asio документация не делает этого.
Я думаю, что ваш вопрос сбивает с толку, но это может помочь:
void receive() {
enum { max_length = 1024 };
char reply[max_length];
size_t reply_length;
std::cout << "Reply is: ";
while ( (reply_length = ba::read(s, basio::buffer(reply, max_length))) > 0) {
std::cout.write(reply, reply_length);
}
std::cout << "\n";
}