2012-06-20 66 views
3

我正在写一个服务器应用程序使用boost :: asio。
我从用户读取的数据的已知量,并将其写入到数据汇已以下API:使用自定义streambuf boost :: asio异步操作

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::streambufboost::asio::basic_streambuf所以它可以处理写入数据的部分呢?

回答

1

对于对象作为缓冲器参数被传递为async_read(),所述缓冲器参数之一:

因此,可以在发生阅读时编写一个与Sink对象交互的自定义​​类。但是,boost::asio::basic_streambuf看起来并不是用作基类的。

如果Sink::write只是对底层内存的抽象,请考虑使用类似于basic_streambuf::prepare()的方法,其中成员函数返回给定大小的缓冲区的句柄。底层的内存实现仍然会在mutable_buffer之后被抽象化。例如:

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

如果Sink::write具有业务逻辑,诸如执行逻辑基于某些字节的值分支,那么它可能需要一个中间缓冲器传递给async_read()。然后用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()'没有任何bussines逻辑。问题是我无法为整个流分配内存。我希望能够分配小缓冲区,并在溢出时将数据传递给'Sink :: write()'。这样,一个boost :: asio :: async_read()会根据需要执行尽可能多的Sink :: write(),然后调用ReadHandler。我没有看到'MuttableBufferSequence'版本如何实现这一点。 – Daszek

+0

我可能不了解溢出的上下文,但是从它的声音中可以看出,它可以通过读取少量数据的async_read循环来解决,写入接收器并继续读取,直到处理完已知的流大小。一旦整个流被处理完毕,它就会调用所需的'ReadHandler'。我的答案的最后部分已被修改,以证明这一点。 –

相关问题