2012-06-20 3 views
3

Я пишу серверное приложение с помощью boost :: asio.
Читаю известное количество данных от пользователя и записать его в приемник данных, который имеет следующий API:Использование пользовательских streambuf с boost :: asio async Операции

class Sink { 
    ... 
    void write(const char *data, size_t size); 
} 

Данные большой и можно назвать write(..) несколько раз обработать один поток.
В моем коде я хотел бы назвать:

boost::asio::async_read(socket, sink_buffer, 
    boost::asio::transfer_exactly(size), ...); 

Можно обернуть Sink с пользовательскими std::streambuf или boost::asio::basic_streambuf поэтому он может обрабатывать написание частей данных к нему?

ответ

1

Для объектов, передаваемых в качестве буферов аргумента для async_read(), то буферов аргумент либо:

  • должен быть тип, который отвечает требованиям MutableBufferSequence.
  • be boost::asio::basic_streambuf объект.

Таким образом, при чтении можно создать пользовательский класс, который взаимодействует с объектом Sink. Тем не менее, boost::asio::basic_streambuf, похоже, не предназначен для использования в качестве базового класса.

Если Sink::write является абстракцией базовой памяти, рассмотрите подход, подобный basic_streambuf::prepare(), где функция-член возвращает дескриптор буфера для заданного размера. Реализация базовой памяти по-прежнему будет абстрагироваться позади mutable_buffer. Например:

boost::asio::async_read(socket, sink.buffer(size), ...); 

Если Sink::write имеет бизнес-логику, например, выполняя логику ветвления на основе значения определенных байт, то это может потребоваться, чтобы передать промежуточный буфер async_read(). Затем вызов Sink::write() с промежуточным буфером будет выполнен из обработчиком. Например:

void handle_read_into_sink(boost::system::error_code error, 
          std::size_t bytes_transferred, 
          boost::asio::ip::tcp::socket& socket, 
          Sink& sink, 
          char* buffer, 
          std::size_t buffer_size, 
          std::size_t bytes_remaining, 
          boost::function< void() > on_finish) 
{ 
    sink.write(buffer, buffer_size); 

    bytes_remaining -= bytes_transferred; 
    // If there are more bytes remaining, then continue reading. 
    if (bytes_remaining) 
    { 
    read_into_sink(socket, sink, buffer, buffer_size, 
        bytes_remaining, on_finish); 
    } 
    // Otherwise, all data has been read. 
    else 
    { 
    on_finish(); 
    } 
} 

void read_into_sink(boost::asio::ip::tcp::socket& socket, 
        Sink& sink, 
        char* buffer, 
        std::size_t buffer_size, 
        std::size_t bytes_remaining, 
        boost::function< void() > on_finish) 
{ 
    boost::asio::async_read(
    socket, boost::asio::buffer(buffer , buffer_size), 
    boost::asio::transfer_exactly(buffer_size), 
    boost::bind(handle_read_into_sink, 
       boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred, 
       boost::ref(socket), 
       boost::ref(sink), 
       buffer, 
       buffer_size, 
       bytes_remaining, 
       on_finish)); 
} 

и начать асинхронный цикл чтения с:

read_into_sink(socket, sink, small_buffer, sizeof_small_buffer, 
       total_stream_size, read_handler_callback); 

Убедитесь, чтобы проверить и обработать ошибки на основе вашей желаемой логики.

+0

Спасибо за быстрый ответ. Мой 'Sink :: write()' не имеет никакой логики бизнеса. Проблема в том, что я не могу выделить память для всего потока. Я надеялся, что я смогу выделить небольшой буфер и передать данные 'Sink :: write()' всякий раз, когда он переполняется. Таким образом, один 'boost :: asio :: async_read()' выполняет как можно больше 'Sink :: write()' s и вызывает 'ReadHandler' впоследствии. Я не вижу, как это может сделать версия MuttableBufferSequence. – Daszek

+0

Возможно, я не понимаю контекста переполнения, но из-за его звуков его можно решить с помощью цикла async_read, который считывает небольшой объем данных, записывает в приемник и продолжает чтение до тех пор, пока не будет обработан известный размер потока. Как только весь поток будет обработан, он вызовет требуемый 'ReadHandler'. Последняя часть моего ответа была изменена, чтобы продемонстрировать это. –

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