青山相待

            白云相爱

            梦不到紫罗袍共黄金带

            一茅斋

            野花开

            管甚谁家兴废谁成败

            陋巷单瓢亦乐哉

            贫,气不改!

            达,志不改!

缓存

从根本上讲,I/O包含了数据从源到目的地的连续内存的传输,这叫做缓存,这些缓存可以简单的描述为包含了一个指针和一组字节数据的元组,然而,为了支持高效网络应用程序的开发,Boost::Asio支持分散-聚合操作,这些操作同时支持一个或多个缓存。
分散读 接收数据并写入多重缓存中。
分散写 传输数据给多个缓存。
因此我们需要一个抽象来代表缓存集合,Boost::Asio的实现方法是定义一个类型(实际上是两个)来代表一个单独的缓存,这些可以被存储在容器中,容器可以被传送给分散聚合操作。
除了指定的缓存是一个指针和一组字节之外,Boost::Asio在可修改内存和不可修改内存(后者是从仓库中创建的const限定变量)之间做了区分,这两种变量可以按照下面的方式定义:
typedef std::pair<void*, std::size_t> mutable_buffer;
typedef std::pair<const void*, std::size_t> const_buffer;
一个可修改的缓存可以转换成const缓存,但反向的转换是禁止的。
然而,Boost::Asio并不使用上述的定义方式,作为替换定义了两个类:mutable_buffer和const_buffer,这样做的目标是为连续的内存提供一个不透明的实现
@std::pair类会自动转换,mutable_buffer 可以自动转换成const_buffer,但反过来就不行。
@这是一个避免缓存泛滥成灾的措施,给定一个缓存的实例,用户只能创建一个另一个buffer来存储同样的内存或者它的一个子集,为了提供进一步的安全性,库也提供了自动判断数组型缓存的大小的机制,boost::array或者std::vector或者std::string。
@违反类型安全的必须显式调用buffer_cast函数,应用程序通常需要避免这样操作,但这样做是必须的,因为需要把原始的内存写入到操作系统的函数接口。
多重缓存可以传递给一个分散聚合操作(比如read()或者write()),方法是把一个缓存对象放到容器里。定义了MutableBufferSequence 和ConstBufferSequence概念来使用std::vector, std::list, std::vector和boost::array这些容器。
继承了io流的流缓存
boost::asio::basic_streambuf 是从std::basic_streambuf 派生的,用来关联有一个或多个具有字符数组类型的对象的输入和输出序列,这些对象可以存储任意的值,这些字符数组对象是流缓存对象的内部对象。也可以直接使用这些对象来执行I/O操作,比如socket上的发送和接收操作:
@流缓存的输入序列可以通过data()成员函数来访问,返回类型符合ConstBufferSequence 
@流缓存的输出序列可以通过prepare()成员函数来访问,返回类型符合MutableBufferSequence 
@调用commit()函数将把数据从输出序列的前端传送到输入序列的末端
@调用consume()将把输入序列前端的数据移除
流缓存接收一个size_t的参数指定了输入序列和输出序列的和的最大值,任何导致长度超过这个限制的操作都会抛出一个std::length_error 异常
buffers_iterator<> 类允许像一段连续内存那样使用缓存序列,也提供了buffers_begin() 和buffers_end(),buffers_iterator<> 的模版参数会被自动推导。
举一个例子,从socket中读出一样并且写入一个std::string,你可以这样写
boost::asio::streambuf sb;
...
std::size_t n = boost::asio::read_until(sock, sb, '\n');
boost::asio::streambuf::const_buffers_type bufs = sb.data();
std::string line
(
boost::asio::buffers_begin(bufs),    
boost::asio::buffers_begin(bufs) + n
);
缓存调试
某些标准库实现,比如Microsoft Visual C++ 8.0及以后的实现,提供了一种迭代器调试的功能,运行时会检查迭代器的有效性,如果使用了一个已经不可用的迭代器,会抛出一个断言
std::vector<int> v(1)
std::vector<int>::iterator i = v.begin();
v.clear(); // invalidates iterators
*i = 0; // assertion!
Boost::Asio利用这些特性增加了缓存调试,请看下面的代码
void dont_do_this()
{
 std::string msg = "Hello, world!";
 boost::asio::async_write(sock, boost::asio::buffer(msg), my_handler);
}
当你调用一个异步读、写操作,需要确保完成句柄调用前缓存都是可用的,在上面的例子,缓存是std::string 变量msg,这是栈上的一个局部变量,在异步操作完成前就退出了作用域,如果足够幸运,应用可能会发生段错误,但更多时候是随机错误。
当buffer调试可用的时候,Boost::Asio在std::string中存储了一个迭代器知道异步操作完成,然后通过废除迭代器来检查缓存的可用性,上面的例子boost::asio::async_write在尝试调用完成端口的时候会抛出一个断言错误。
在Microsoft Visual Studio 8.0 或者更新一些的版本以及GCC定义了_GLIBCXX_DEBUG 的时候自动开启这项特性,开启这项特性会有性能开销,因此缓存调试只应该在debug版本中开启,在其他编译器中通过定义BOOST_ASIO_ENABLE_BUFFER_DEBUGGING来开启,也可以通过定义BOOST_ASIO_DISABLE_BUFFER_DEBUGGING来显式关闭这项特性。
流缓存英文:streambuf
posted @ 2016-03-13 15:17  Leo.Z  阅读(236)  评论(0编辑  收藏  举报