使用自定义streambuf和boost :: asio异步操作

时间:2012-06-20 13:32:02

标签: c++ boost-asio

我正在使用boost :: asio编写服务器应用程序 我正在从用户读取已知数量的数据并将其写入具有以下api的数据接收器:

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

数据很大,可以多次调用write(..)来处理一个流 在我的代码中,我想打电话:

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

是否可以使用自定义Sinkstd::streambuf打包boost::asio::basic_streambuf,以便它可以处理向其写入数据部分?

1 个答案:

答案 0 :(得分:1)

对于作为async_read() buffers 参数传递的对象,缓冲区参数:

因此,可以在读取时编写与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()将从async_read()处理程序中完成。例如:

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 );

确保根据您所需的逻辑检查并处理错误