2014-01-14 3 views
2

У меня есть очень простой метод, с целью ответа на входящее сообщение, а затем закрывая соединение:повышение :: ASIO :: async_write и буферы более 65536 байт

void respond (const std::string message) 
{ 
    std::string str = "<?xml version=\"1.0\"?>"; 

    Controller & controller = Controller::Singleton(); 
    if (auto m = handleNewMessage(_message)) 
    { 
    auto reply = controller.FIFO(m); 
    str.append(reply); 
    } 
    else 
    str.append ("<Error/>"); 

    std::size_t bytes = str.size() * sizeof(std::string::value_type); 
    std::cout << "Reply bytesize " << bytes << std::endl; 

    boost::asio::async_write(
      socket_, 
      boost::asio::buffer(str), 
      boost::bind(
        &TCPConnection::handle_write, 
        shared_from_this(), 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred 
       )); 
} 


void handle_write (const boost::system::error_code & error, size_t bytes_transferred) 
{ 
    if (error) 
    { 
    std::cerr << "handle_write Error: " << error.message() << std::endl; 
    std::cerr << "handle_write Bytes sent: " << bytes_transferred << std::endl; 
    } 
    else 
    { 
     std::cerr << "handle_write Bytes sent: " << bytes_transferred << std::endl; 
     socket_.close(); 
    } 
} 

Я знаю, что проблема что повышение :: ASIO :: async_write не завершает операцию записи, так как выход из вышеуказанных операций:

Reply bytesize: 354275 
handle_write Bytes sent: 65536 

Подразумевая, что максимальный размер буфера (65536) не было достаточно, чтобы записать данные?

Поиск по всем Stack Overflow, я обнаружил, что моя проблема в том, что буфер, созданный метод:

boost::asio::buffer(str) 

выходит из области видимости перед операцией имеет шанс закончить отправку всех данных.

Похоже, я не могу использовать повышение :: ASIO :: mutable_buffer, но только повышение :: ASIO :: streambuf

Кроме того, и что более важно, вторая ошибка жалуется на фактический прирост :: ASIO :: async_write передается импульс :: ASIO :: const_buffer ИЛИ повышение :: ASIO :: mutable_buffer:

/usr/include/boost/asio/detail/consuming_buffers.hpp:164:5: error: no type named ‘const_iterator’ in ‘class boost::asio::mutable_buffer’ 
    const_iterator; 
    ^
/usr/include/boost/asio/detail/consuming_buffers.hpp:261:36: error: no type named ‘const_iterator’ in ‘class boost::asio::mutable_buffer’ 
    typename Buffers::const_iterator begin_remainder_; 

Так я остался только один выбор: Для того, чтобы использовать импульс :: ASIO :: streambuf

Я попытался использовать:

boost::asio::streambuf _out_buffer; 

В качестве члена класса, а затем сделал метод ответа:

std::ostream os(&_out_buffer); 
    os << str; 

    boost::asio::async_write(
      socket_, 
      _out_buffer, 
      boost::asio::transfer_exactly(bytes), 
      boost::bind(
        &TCPConnection::handle_write, 
        shared_from_this(), 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred 
       )); 

Однако, хотя я не получаю ошибки, не все данные передаются! Итак, я предполагаю, что вся строка не записана в streambuf?

В качестве альтернативы, я хотел бы знать, что является самым элегантным способом записи, используя boost :: asio :: async_write, данные размером более 65536 байтов!

ответ

1

Алекс, вы понимаете, ASIO асинхронное операции неправильно. Ваша проблема связана с временем жизни буфера и сокета. Буфер должен быть активным и сокет открыт в течение всего времени передачи (от asio::async_write звонок handle_write callback должен вызываться Asio io_service диспетчер. Чтобы лучше понять, как это работает, считайте, что каждый раз, когда вы делаете boost::asio::async_{operation}, вы отправляете указатель на данные для операции и указатель на функцию обратного вызова в очередь заданий. И это решение Asio, когда вы выполняете свою работу (но, конечно, она пытается сделать это как можно быстрее =)). Когда все (возможная большая) операция ввода-вывода завершается, Asio информирует вас об использовании указанного обратного вызова. И вы можете свободно освобождать ресурсы.

Итак, чтобы получить код, вы должны быть уверены, что std::string str по-прежнему существует и _socket не закрыт до handle_write обратного вызова. Вы можете заменить выбранный стек переменной std::string str на некоторую переменную-член в классе, который агрегирует _socket. И передвиньте линию socket_.close(); от respond до handle_write.

Надеюсь, я вам помог.

P.S. Когда вы делаете boost::asio::buffer(str),, вы не копируете содержимое строки, а просто создаете тонкий wpapper над данными строки.

+0

Да, вы действительно помогли! Совсем мгновение назад я переместил сокет вплотную к беспрецедентному handle_write! ОДНАКО, проблема все еще остается, даже при использовании streambuf, все содержимое не отправляется, хотя больше нет ошибки –

+0

Как насчет времени жизни буфера? Он жив в течение всего времени передачи? – inkooboo

+0

Да, он создается во время метода ответа и не изменяется до тех пор, пока объект класса не будет удален asio. У меня есть подозрение, что не все части строки скопированы, не знаю, правильно ли я копирую строку в streambuf. –

1

Код:

_out_buffer(static_cast<void*>(&str.front()), bytes); 

действителен только при инициализации _out_buffer, то есть перед началом тела конструктора вашего класса.

Этот код эквивалентен

_out_buffer.operator()(static_cast<void*>(&str.front()), bytes) 

Конечно нет такого оператора в классе mutable_buffer, и это то, что компилятор жалуется.

Я думаю, что проще всего сделать (но не самый лучший), чтобы изменить эту линию:

_out_buffer = boost::asio::mutable_buffer(
    static_cast<void*>(&str.front()), 
    bytes 
); 
+0

Спасибо за ответ! Я уже пробовал mustable_buffer. Да, он построен нормально, но проблема остается, boost :: asio :: async_write не нравится как параметр (такая же ошибка, как и раньше). –

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