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";
}