• 缓存


    从根本上讲,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, ' ');
    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
  • 相关阅读:
    网益云——冲刺博客0
    网益云——软件工程之现场编程实战
    2020福州大学软件工程实践个人总结
    2020福州大学软件工程实践结对编程作业二
    福州大学软件工程实践个人编程作业
    2020软工第一次作业
    C. Present(二分 + 扫描线)
    P1287 盒子与球
    错排
    Codeforces 1323 D. Present (思维)
  • 原文地址:https://www.cnblogs.com/learn-my-life/p/5272123.html
Copyright © 2020-2023  润新知