【boost网络库从青铜到王者】第三篇:asio网络编程中的buffer缓存数据结构

文章目录

  • 1、关于buffer数据结构
      • 1.1、简单概括一下,我们可以用buffer() 函数生成我们要用的缓存存储数据。
      • 1.2、但是这太复杂了,可以直接用buffer函数转化为send需要的参数类型:
      • 1.3、output_buf可以直接传递给该send接口。我们也可以将数组转化为send接受的类型
      • 1.4、对于流式操作,我们可以用streambuf,将输入输出流和streambuf绑定,可以实现流式输入和输出

1、关于buffer数据结构

任何网络库都有提供buffer的数据结构,所谓buffer就是接收和发送数据时缓存数据的结构

boost::asio提供了asio::mutable_bufferasio::const_buffer这两个结构,他们是一段连续的空间,首字节存储了后续数据的长度。

asio::mutable_buffer用于写服务,asio::const_buffer用于读服务。但是这两个结构都没有被asioapi直接使用。

对于apibuffer参数,asio提出了MutableBufferSequenceConstBufferSequence概念,他们是由多个asio::mutable_bufferasio::const_buffer组成的。也就是说boost::asio为了节省空间,将一部分连续的空间组合起来,作为参数交给api使用。

我们可以理解为MutableBufferSequence的数据结构为std::vector<asio::mutable_buffer>

结构如下:
在这里插入图片描述
每隔vector存储的都是mutable_buffer的地址,每个mutable_buffer第一个字节表示数据的长度,后面跟着数据内容。

这么复杂的结构交给用户使用并不合适,所以asio提出了buffer()函数,该函数接收多种形式的字节流,该函数返回asio::mutable_buffers_1 或者asio::const_buffers_1结构的对象。

如果传递给buffer()的参数是一个只读类型,则函数返回asio::const_buffers_1 类型对象。

如果传递给buffer()的参数是一个可写类型,则返回asio::mutable_buffers_1 类型对象。

asio::const_buffers_1asio::mutable_buffers_1asio::mutable_bufferasio::const_buffer的适配器,提供了符合MutableBufferSequenceConstBufferSequence概念的接口,所以他们可以作为boost::asioapi函数的参数使用。

1.1、简单概括一下,我们可以用buffer() 函数生成我们要用的缓存存储数据。

比如boost的发送接口send要求的参数为ConstBufferSequence类型:

template<typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence & buffers);

我们需要将 “Hello World” 类型转换为该类型。

void BoostAsio::UseConstBuffer(std::string& buffer) {boost::asio::const_buffer asio_buff(buffer.c_str(), buffer.length());std::vector<boost::asio::const_buffer> buffer_sequence;buffer_sequence.emplace_back(asio_buff);
}

这段代码使用了C++编程语言和Boost.Asio库来处理网络和异步I/O操作。代码主要功能是从一个std::string对象创建一个Boost.Asio的const_buffer,然后将这个const_buffer添加到一个const_buffer对象的向量中,通常在需要使用Boost.Asio进行网络数据传输时会这样做。

  • UseConstBuffer函数:UseConstBuffer函数以一个引用参数buffer作为输入。函数的目的是创建一个const_buffer,然后将其添加到一个const_buffer对象的向量中。

  • 创建const_buffer:代码使用buffer.c_str()(字符串c风格表示)和buffer.length()(字符串长度)作为参数,创建了一个名为asio_buffconst_bufferconst_buffer表示一个常量数据的缓冲区,用于读取操作。

  • 准备缓冲区序列:创建一个名为buffer_sequencestd::vector,用于存储boost::asio::const_buffer的实例。emplace_back函数将asio_buff添加到buffer_sequence中。

  • 到此为止,buffer_sequence中会包含一个代表输入std::string的const_buffer

  • 然而,有一个重要的方面需要考虑:buffer_sequence的作用域。目前,buffer_sequence是在UseConstBuffer函数内部定义的局部变量。如果你希望在函数外部使用buffer_sequence,你需要通过返回值或通过引用参数将其传递出来。

  • 另外,请确保在代码的其他部分使用了buffer_sequence来进行实际的网络操作,例如使用Boost.Asio函数将数据发送到网络套接字上。

  • 最后,记得正确处理buffer参数引用的std::string对象的生命周期。由于const_buffer引用了字符串的底层字符数据,确保在使用缓冲区期间字符串保持有效。

emplace_back()和push_back()的区别:
在你的代码中,使用了emplace_back()函数来将asio_buff添加到buffer_sequence中。emplace_back()是C++标准库中std::vector的一个函数,用于在容器的末尾构造一个新元素。

与之相比,push_back()函数是另一个向std::vector中添加元素的函数,但它要求你传递一个已构造的元素(对象)。这意味着如果你使用push_back(),你需要首先创建一个const_buffer对象,然后将其传递给函数。而使用emplace_back(),你可以直接在容器中构造新元素,而不需要提前创建对象。

总的来说,emplace_back()通常会比 push_back() 更高效,因为它可以避免额外的对象构造和拷贝操作。在你的代码中,使用emplace_back()来添加asio_buff是一个不错的选择,因为它允许直接在容器中构造const_buffer对象。

  • 对象构造次数:

    • push_back()接受一个已经构造好的对象,并将其副本添加到容器中。这意味着对象需要在调用push_back()之前构造好,然后在添加到容器时还需要执行拷贝构造或移动构造操作。
    • emplace_back()在容器内部直接构造对象,避免了先构造然后拷贝或移动的步骤。它会将传递的参数直接用于对象的构造。
  • 拷贝和移动操作:

    • 在使用push_back()时,如果添加的对象是已经构造好的,就需要执行一次拷贝构造(如果容器中的对象类型支持拷贝构造)或移动构造(如果支持移动构造)操作,将对象的副本添加到容器中。
    • 使用emplace_back()时,对象会直接在容器内部构造,避免了拷贝和移动操作。
  • 内存分配:

    • 当使用push_back()添加对象时,它首先会分配内存用于存储对象的副本,然后执行拷贝或移动操作,最后调整容器的大小。这可能涉及到多次内存分配和释放。
    • 使用emplace_back()时,它直接在容器内构造对象,避免了额外的内存分配和释放。
    • 总之,emplace_back()通常更高效,因为它在容器内部直接构造对象,避免了额外的拷贝和移动操作,以及不必要的内存分配和释放。这使得在需要向容器添加构造对象的情况下,emplace_back()更为优越。

1.2、但是这太复杂了,可以直接用buffer函数转化为send需要的参数类型:

void BoostAsio::UseConstBuffer1(std::string& buffer) {boost::asio::const_buffers_1 out_buffer(boost::asio::buffer(buffer));
}

代码段中使用了Boost.Asio库来创建一个const_buffers_1对象,并通过boost::asio::buffer(buffer)std::string转换为用于网络传输的缓冲区。让我对这段代码进行解释:

  • 函数名称和参数:

    • 这个函数名是UseConstBuffer1,它接受一个std::string&类型的参数buffer,传入的字符串是要被发送的数据。
  • 创建const_buffers_1对象:

    • const_buffers_1Boost.Asio库中的一个类,用于包装一个常量缓冲区,以便进行异步I/O操作。
    • 通过boost::asio::buffer(buffer),将buffer(std::string)转换为一个Boost.Asio缓冲区对象。

在代码中,尽管你创建了一个const_buffers_1对象,但是这个对象在函数结束后会被销毁,所以你需要在代码中继续使用这个对象进行实际的网络操作,例如发送数据到套接字。

1.3、output_buf可以直接传递给该send接口。我们也可以将数组转化为send接受的类型

void BoostAsio::UseBufferArray() {const size_t buf_size = 30;std::unique_ptr<char[]> buf(new char[buf_size]);auto input_buf = boost::asio::buffer(static_cast<void*>(buf.get()), buf_size);
}

这段代码执行以下操作:

  • 定义缓冲区大小:

    • buf_size 是一个常量,表示缓冲区的大小,这里设置为 30 字节。
  • 创建缓冲区数组:

    • 使用 std::unique_ptr 创建了一个 char 数组,大小为 buf_size
    • std::unique_ptr<char[]> 是一个智能指针,用于管理动态分配的 char 数组。这样做可以在结束作用域时自动释放内存。
  • 创建输入缓冲区:

    • 使用 boost::asio::buffer 函数创建了一个输入缓冲区。
    • buffer 函数的第一个参数是一个 void* 指针,它指向数据的起始地址。在这里,使用 buf.get() 获取 std::unique_ptr 所管理的原始指针。
    • 第二个参数是缓冲区的大小,即 buf_size

总之,这段代码的目的是创建一个大小为 30 字节的输入缓冲区,其中使用了 std::unique_ptr 来管理动态分配的内存。这个缓冲区可以在异步 I/O 操作中使用,比如异步读取数据到这个缓冲区中。记得在实际应用中,你需要使用 boost::asio::io_context 和套接字等组件来实现具体的异步 I/O 操作。

1.4、对于流式操作,我们可以用streambuf,将输入输出流和streambuf绑定,可以实现流式输入和输出

id use_stream_buffer() {asio::streambuf buf;std::ostream output(&buf);// Writing the message to the stream-based buffer.output << "Message1\nMessage2";// Now we want to read all data from a streambuf// until '\n' delimiter.// Instantiate an input stream which uses our // stream buffer.std::istream input(&buf);// We'll read data into this string.std::string message1;std::getline(input, message1);// Now message1 string contains 'Message1'.
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/38554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker发展历史

docker 一、docker发展历史很久以前2013年2014年2015年2016年2017年2018年2019年及未来 二、 docker概述定义&#xff1a;docker底层运行原理:docker简述核心概念容器特点Docker与虚拟机的区别: 三、容器在内核中支持两种重要技术四、namespace的六项隔离五、虚拟化产品有哪些1…

CAS 的执行流程 ?CAS 中 ABA 问题如何解决 ?CAS 在 Java 中有哪些实现类 ?

目录 1. CAS 的执行流程 2. CAS 中的 ABA 问题 3. 如何解决 CAS 中的 ABA 问题 4.CAS 在Java 中的实现类有哪些 1. CAS 的执行流程 CAS 比较并替换的大致流程是这样的&#xff1a; 它有三个操作单位&#xff1a;V&#xff08;内存值&#xff09;&#xff0c;A&#xff08;…

3D沉浸式旅游网站开发案例复盘【Three.js】

Plongez dans Lyon网站终于上线了。 我们与 Danka 团队和 Nico Icecream 共同努力&#xff0c;打造了一个令我们特别自豪的流畅的沉浸式网站。 这个网站是专为 ONLYON Tourism 和会议而建&#xff0c;旨在展示里昂最具标志性的活动场所。观看简短的介绍视频后&#xff0c;用户…

Android 面试笔记整理-Binder机制

作者&#xff1a;浪人笔记 面试可能会问到的问题 从IPC的方式问到Binder的优势为什么zygote跟其他服务进程的通讯不使用BinderBinder线程池和Binder机制 等等这些问题都是基于你对Binder的理解还有对其他IPC通讯的理解 IPC方式有多少种 传统的IPC方式有Socket、共享内存、管道…

云计算虚拟仿真实训平台

一、云计算虚拟仿真系统概述 云计算虚拟仿真系统是一种基于云计算技术和虚拟化技术的系统&#xff0c;用于实现各种仿真和模拟任务。它可以提供强大的计算能力和资源管理&#xff0c;为用户提供灵活、高效、可扩展的仿真环境。 该系统通常由一组服务器、网络和存储设备组成&am…

uniapp开发小程序-有分类和列表时,进入页面默认选中第一个分类

一、效果&#xff1a; 如下图所示&#xff0c;进入该页面后&#xff0c;默认选中第一个分类&#xff0c;以及第一个分类下的列表数据。 二、代码实现&#xff1a; 关键代码&#xff1a; 进入页面时&#xff0c;默认调用分类的接口&#xff0c;在分类接口里做判断&#xff…

神经网络基础-神经网络补充概念-08-逻辑回归中的梯度下降算法

概念 逻辑回归是一种用于分类问题的机器学习算法&#xff0c;而梯度下降是优化算法&#xff0c;用于更新模型参数以最小化损失函数。在逻辑回归中&#xff0c;我们使用梯度下降算法来找到最优的模型参数&#xff0c;使得逻辑回归模型能够更好地拟合训练数据。 逻辑回归中的梯…

无监督学习之主成分分析-半导体制造高维数据如何降维

数据降维不只存在于半导体数据中&#xff0c;它是存在于各行各业的&#xff0c;我们要分析的数据维数较多的时候全部输入维数较大这时就要采取降维的方法综合出主要的几列用于我们的分析。 PCA的哲学理念是要抓住问题的主要矛盾进行分析&#xff0c;是将多指标转化为少数几个…

前端技术栈es6+promise

let入门使用、 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>let 基本使用</title><script type"text/javascript">let name "hspedu教育";//老韩解读//1. conso…

苹果Mac像Windows一样使用

一、将磁盘访问设置的像Windows一样&#xff1a; 1.1、点击任务栏第一个按钮打开“访达”&#xff0c;点击菜单栏上的访达-偏好设置&#xff1a; 1.2、勾选“硬盘”&#xff0c;这样macOS的桌面上就会显示一个本地磁盘&#xff0c;之后重命名为磁盘根&#xff0c;相当于window…

SPF9139全力适配ios16与鸿蒙3.0,超实用数据提取、分析、恢复能力UP!

​ 如今&#xff0c;群聊已成为人们必不可少的沟通窗口 家人群&#xff0c;好友群&#xff0c;班级群 粉丝群&#xff0c;交友群&#xff0c;工作群 …… 各类群聊铺天盖地般涌来的同时 也有一些群聊沦为了 赌博、传播淫秽视频、发表不当言论 等违法犯罪行为滋生之地 与…

mac 可以进行单片机(stm32)的开发吗?

当涉及到在Mac上进行单片机开发时&#xff0c;是完全可行的。以下是为什么Mac适合单片机开发的解释&#xff1a;开发工具&#xff1a;针对STM32单片机&#xff0c;你可以使用多种开发工具。一个常用的选择是Segger Embedded Studio&#xff0c;它是一个功能强大的集成开发环境&…

ClickHouse(十八):Clickhouse Integration系列表引擎

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术&#xff0c;IT贫道_Apache Doris,大数据OLAP体系技术栈,Kerberos安全认证-CSDN博客 &…

IDEA常用设置与maven项目部署

目录 前言 一、Idea是什么 二、Idea的优点 三、Idea的常用设置 主题设置 设置鼠标悬浮提示 忽略大小写提示 自动导包 取消单行显示Tabs 设置字体 配置类文档注释信息模版 设置文件编码 设置自动编译 水平或者垂直显示代码 快捷方式改成eclipse 设置默认浏览器…

Java并发编程(六)线程池[Executor体系]

概述 在处理大量任务时,重复利用线程可以提高程序执行效率,因此线程池应运而生。 它是一种重用线程的机制,可以有效降低内存资源消耗提高响应速度。当任务到达时&#xff0c;任务可以不需要的等到线程创建就能立即执行线程池可以帮助我们更好地管理线程的生命周期和资源使用,…

Jmeter - 函数助手

目录 __StringFromFile __CSVRead __counter __RandomString __StringFromFile StringFromFile函数用于获取文本文件的值&#xff0c;一次读取一行 1、输入文件的全路径&#xff1a;填入文件路径 2、存储结果的变量名&#xff08;可选&#xff09; 3、Start file sequence …

Tomcat+Http+Servlet

文章目录 1.HTTP1.1 请求和响应HTTP请求&#xff1a;请求行请求头请求体HTTP响应&#xff1a;响应行&#xff08;状态行&#xff09;响应头响应体 2. Apache Tomcat2.1 基本使用2.2 IDEA中创建 Maven Web项目2.3 IDEA中使用Tomcat 3. Servlet3.1 Servlet快速入门3.2 Servlet执行…

游戏中的UI适配

引用参考&#xff1a;感谢GPT UI适配原理以及常用方案 游戏UI适配是确保游戏界面在不同设备上以不同的分辨率、屏幕比例和方向下正常显示的关键任务。下面是一些常见的游戏UI适配方案&#xff1a; 1.分辨率无关像素&#xff08;Resolution-Independent Pixels&#xff09;&a…