2013-02-25 4 views
6

У меня есть две следующие функции для отправки и получения пакетов.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? Другой вопрос: как предотвратить переполнение буфера?

ответ

15

Чтобы получить размер буфера, можете использовать функцию boost::asio::buffer_size(). Однако в вашем примере это, скорее всего, будет мало пользы для вас.

Как поясняется в буфере overview, Boost.Asio использует классы буфера для представления буферов. Эти классы обеспечивают абстракцию и защищают операции Boost.Asio от переполнения буфера. Хотя результат boost::asio::buffer() передан в операции, метаданные, такие как размер буфера или его базового типа, не передаются. Кроме того, эти буферы не владеют памятью, поэтому ответственность за приложения лежит на том, чтобы гарантировать, что базовая память остается в силе в течение всего времени жизни абстракции буфера.

Функция boost::asio::buffer() обеспечивает удобный способ создания классов буфера, где размер буфера выводится из возможного типа. Когда Boost.Asio способен вывести длину буфера, операции Boost.Asio не будут вызывать переполнение буфера при использовании результирующего типа буфера. Однако, если код приложения указывает размер буфера на boost::asio::buffer(), то ответственность за приложения заключается в том, чтобы размер не превышал базовую память.

При чтении данных требуется буфер. Основной вопрос заключается в том, как узнать, сколько памяти выделяется, если Boost.Asio не передает размер. Есть несколько решений этой проблемы:

  • запроса сокет для сколько данных доступно через socket::available(), а затем выделить буфер соответствующим образом.

    std::vector<char> data(socket_.available()); 
    boost::asio::read(socket_, boost::asio::buffer(data)); 
    
  • Используйте класс, который Boost.Asio может расти в памяти, такие как boost::asio::streambuf. Некоторые операции, такие как boost::asio::read(), принимают streambuf объекты в качестве их буфера и выделяют память, как требуется для операции. Однако должно быть предусмотрено условие завершения; в противном случае операция будет продолжаться до тех пор, пока буфер не будет заполнен.

    boost::asio::streambuf data; 
    boost::asio::read(socket_, data, 
            boost::asio::transfer_at_least(socket_.available())); 
    
  • В Öö Tiib предполагает, включают длину, как часть протокола связи. Проверьте примеры протоколов связи Boost.Asio examples. Сосредоточьтесь на протоколе, не обязательно на Boost.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.  
      
+0

Отличный материал. 'boost :: asio :: streambuff' с' boost :: asio :: read_until() 'работал хорошо для меня в случае, когда сообщения заканчиваются разделителем. –

1

Я думаю, что ваш вопрос сбивает с толку, но это может помочь:

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

Параметр 'подталкивание :: ASIO :: буфер (,)' возвращает то, что именно. Я вижу, что он возвращает что-то в 'ba :: read (s, buffer (,))', но что это? – pandoragami

+0

@lost_with_coding: Тип, который представляет память, но не имеет памяти. [Функция] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/buffer.html) помогает адаптировать обычно используемые типы, чтобы они соответствовали требованиям типа для многих из Boost .Asio-операции. Этот [обзор] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/overview/core/buffers.html) содержит некоторую информацию. –

+0

Вам не нужно передавать max_length в asio :: buffer() в этом примере. (Так как asio может получить его с помощью 'sizeof'.) –

5

Обычно протокол связи либо использует сообщения фиксированной длины или сообщения, содержащие заголовок, сообщающий длину сообщения.

Boost.Asio online documentation содержит большой набор примеров и руководств, поэтому вы должны начать с этого момента. Википедия является хорошим источником для объяснения терминов, но не для этого.

+1

Я уже просмотрел обучающие материалы по ускорению, но они просто замаскировали примеры и не очень подробно объясняют, что вызывает функция, что они возвращают и т. Д. Я знаю, что могу также заглянуть в файлы hpp, но это похоже на иглу в стоге сена и даже более бесполезную, чем сами примеры. PLUS. Я уверен, что в примерах/обучающих примерах не сказано много вещей, но только в файлах hpp, которые могут потребовать много лет практики, чтобы потреблять. – pandoragami

+0

@lost_with_coding, возможно, примеры boost asio ожидают, что люди будут знакомы с концепцией цифровой коммуникации и значением связанных терминов, таких как protcols, клиенты, серверы, запросы и т. Д., Используемые в примерах. Я предлагаю отказаться от разработки таких знаний из кода, есть более простые источники, чтобы узнать все это. –

+0

@lost_with_coding: [примеры] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html) не объясняют, что делает API, потому что это документировано в [ссылке ] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference.html). Библиотека Boost.Asio сложна, а не сложна. В документации имеется большой объем информации, и, возможно, стоит потратить время на ознакомление с различными частями документации. –

Смежные вопросы