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

news/2024/5/15 19:22:55/文章来源:https://blog.csdn.net/qq_44918090/article/details/132294793

文章目录

  • 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.luyixian.cn/news_show_345600.aspx

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

相关文章

PyQt5资源的加载和使用,即如何使用Pyrcc

1、打开QtDesigner&#xff0c;选择编辑资源 2、新建资源文件&#xff0c;随便找个地方保存 3、按照自己的喜好命名&#xff0c;然后添加资源 4、保存并退出 5、我们创建一个QLabel&#xff0c;在这里添加资源 6、我们保存界面文件&#xff0c;并编译为py文件&#xff0c;然后…

SpringBoot + Mybatis多数据源

一、配置文件 spring: # datasource: # username: root # password: 123456 # url: jdbc:mysql://127.0.0.1:3306/jun01?characterEncodingutf-8&serverTimezoneUTC # driver-class-name: com.mysql.cj.jdbc.Driverdatasource:# 数据源1onedata:jdbc-url: j…

【5款登录验证校验】基于jquery实现的5款登录验证码组件(附完整源码)

文章目录 写在前面涉及知识点1、随机字母验证码1.1 效果1.2 实现源码 2、数字运算验证码2.1 效果2.2 实现源码 3、滑块验证码3.1 效果3.2 实现源码 4、图片补全验证码4.1 效果4.2 实现源码 5、顺序点选验证码5.1 效果5.2 实现源码 6、源码分享6.1 百度网盘6.2 123网盘6.3 邮箱留…

基于STM32的超声波雷达

视频地址:1.基于STM32的超声波雷达-演示_哔哩哔哩_bilibili 备注:文档最后有所有文件的网盘地址 1. 项目展示 1.1. 最终效果 1.2. 项目硬件 全部必要硬件(左到右): ST-LINK调试器:调试下载程序stm32f103c8t6核心板1.8寸TFT显示器sg90舵机超声波传感器

Cpp学习——string模拟实现

目录 一&#xff0c;string的成员变量 二&#xff0c;string的各项功能函数 1.构造函数 2.析构函数 3.扩容函数 4.插入与删除数据的函数 5.运算符重载 6.打印显示函数 7&#xff0c;拷贝构造 8.find函数 一&#xff0c;string的成员变量 在模拟实现string之前&#xff…

k8s 自身原理之 Service

好不容易&#xff0c;终于来到 k8s 自身的原理之 关于 Service 的一部分了 前面我们用 2 个简图展示了 pod 之间和 pod 与 node 之间是如何通信息的&#xff0c;且通信的数据包是不会经过 NAT 网络地址转换的 那么 Service 又是如何实现呢&#xff1f; Service 我们知道是用…

mysql-事务特性以及隔离机制

一.ACID 事务&#xff08;Transaction&#xff09;是访问和更新数据库的程序执行单元&#xff1b;事务中可能包含一个或多个sql语句&#xff0c;这些语句要么都执行&#xff0c;要么都不执行。 1.逻辑架构和存储引擎 如上图所示&#xff0c;MySQL服务器逻辑架构从上往下可以分…

麦肯锡发布《2023年度科技报告》!

在经历了 2022 年技术投资和人才的动荡之后&#xff0c;2023 年上半年&#xff0c;人们对技术促进商业和社会进步的潜力重新燃起了热情。生成式人工智能&#xff08;Generative AI&#xff09;在这一复兴过程中功不可没&#xff0c;但它只是众多进步中的一个&#xff0c;可以推…

vue 路由地址把#去掉

在路由对象里边添加history模式就不显示# mode:history // 4.通过规则创建对象 const router new VueRouter({routes,// 默认模式为hash 带# // history 不带#mode:history })想把端口号8000换成其他的 比如我这样的3000更换端口号教程

自动化测试用例设计实例

在编写用例之间&#xff0c;笔者再次强调几点编写自动化测试用例的原则&#xff1a; 1、一个脚本是一个完整的场景&#xff0c;从用户登陆操作到用户退出系统关闭浏览器。 2、一个脚本脚本只验证一个功能点&#xff0c;不要试图用户登陆系统后把所有的功能都进行验证再退出系统…

【声波】声波在硼酸、硫酸镁 (MgSO4) 和纯水中的吸收研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

部署工业物联网可以选择哪些通信方案?

部署工业物联网有诸多意义&#xff0c;诸如提升生产效率&#xff0c;降低管理成本&#xff0c;保障生产品质稳定&#xff0c;应对长期从业劳动力变化趋势等。针对不同行业、场景&#xff0c;工业物联网需要选择不同的通信方案&#xff0c;以达到成本和效益的最佳平衡。本篇就简…

05-基础入门-系统及数据库等

基础入门-系统及数据库等 一、操作系统层面1、识别操作系统常见方法2、简要两者区别及识别意义3、操作系统层面漏洞类型对应意义4、简要操作系统层面漏洞影响范围 二、数据库层面1、识别数据库类型常见方法2、数据库类型区别及识别意义3、数据库常见漏洞类型及攻击4、简要数据库…

无涯教程-Perl - setpwent函数

描述 此功能将枚举设置(或重置)到密码条目集的开头。应该在第一次调用getpwent之前调用此函数。 语法 以下是此函数的简单语法- setpwent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile(($name, $passwd, $uid, $gid, $quota, …

3. 爬取自己CSDN博客列表(自动方式)(分页查询)(网站反爬虫策略,需要在代码中添加合适的请求头User-Agent,否则response返回空)

文章目录 步骤打开谷歌浏览器输入网址按F12进入调试界面点击网络&#xff0c;清除历史消息按F5刷新页面找到接口&#xff08;community/home-api/v1/get-business-list&#xff09;接口解读 撰写代码获取博客列表先明确返回信息格式json字段解读 Apipost测试接口编写python代码…

laravel框架中批量更新数据

在php框架中 tp中就有批量更新封装好的 SaveAll 在laravel中有批量插入没有批量更新操作;因此我们可以自己去封装一个 然后批量进行更新操作 封装参考代码: /*** 批量更新** param $tableName 表名称* param string $pk 更新的字段* param array $multipleData 要更新的数据*…

外企开展中国在线业务的三种网络加速方案:含免ICP备案CDN解决方案

中国作为全球除美国外最大的消费市场&#xff0c;是几乎每个国际化企业都想要深入挖掘的市场&#xff0c;但外国企业在中国开展在线业务需要面临一个比较特殊的挑战&#xff1a;互联网防火墙&#xff08;GFW&#xff09;。为此所有想要在中国市场有所作为的外企都需要首先解决这…

iptables之iptables表、链、规则 、匹配模式、扩展模块、连接追踪模块(一)

一、iptables的链 1.请求到达本机&#xff1a; PREROUTING --> INPUT --> Local Process &#xff08;本机&#xff09; 2.请求经过本机&#xff1a; PREROUTING --> FORWARD --> POSTROUTING 3.请求从本机发出&#xff1a;local Process&#xff08;本机&#xf…

第三方软件安全测评如何收费,安全测试包括哪些测试项?

近年来&#xff0c;随着全球范围内网络安全事件的频发&#xff0c;第三方软件安全测评的需求也日益增长。软件安全对于企业的重要性不言而喻&#xff0c;那么如何收费和可做测试项就成了企业最为关注的问题&#xff0c;小编将就以上问题作出以下简析。 一、第三方软件安全测评…

Postman接口自动化测试实例

一.实例背景 在实际业务中&#xff0c;经常会出现让用户输入用户密码进行验证的场景。而为了安全&#xff0c;一般都会先请求后台服务器获取一个随机数做为盐值&#xff0c;然后将盐值和用户输入的密码通过前端的加密算法生成加密后串传给后台服务器&#xff0c;后台服务器接到…