Для объектов, передаваемых в качестве буферов аргумента для 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);
Убедитесь, чтобы проверить и обработать ошибки на основе вашей желаемой логики.
Спасибо за быстрый ответ. Мой 'Sink :: write()' не имеет никакой логики бизнеса. Проблема в том, что я не могу выделить память для всего потока. Я надеялся, что я смогу выделить небольшой буфер и передать данные 'Sink :: write()' всякий раз, когда он переполняется. Таким образом, один 'boost :: asio :: async_read()' выполняет как можно больше 'Sink :: write()' s и вызывает 'ReadHandler' впоследствии. Я не вижу, как это может сделать версия MuttableBufferSequence. – Daszek
Возможно, я не понимаю контекста переполнения, но из-за его звуков его можно решить с помощью цикла async_read, который считывает небольшой объем данных, записывает в приемник и продолжает чтение до тех пор, пока не будет обработан известный размер потока. Как только весь поток будет обработан, он вызовет требуемый 'ReadHandler'. Последняя часть моего ответа была изменена, чтобы продемонстрировать это. –