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

news2024/10/5 7:10:28

文章目录

  • 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.coloradmin.cn/o/883082.html

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

相关文章

一百五十五、Kettle——Linux上安装的kettle9.3连接MySQL数据库

一、目的 kettle9.3在Linux上成功安装后&#xff0c;就建立数据库连接&#xff0c;第一个就是MySQL数据库 二、前提准备 提前准备好MySQL驱动包 &#xff08;一&#xff09;MySQL版本 &#xff08;二&#xff09;注意&#xff1a;由于我的MySQL版本比较高&#xff0c;所以特…

vue 路由地址把#去掉

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

【实际开发19】- 压测 / 调优准备

目录 1. Jmeter 2. Jmeter 环境部署 1. 配置 : 临时修改语言 ~ Options → Choose Language → Chinese 3. Jmeter 并发测试 0. 提示 : Postman 测试是“串行”的 , 无法测试并发请求 1. daiding 1. Jmeter 下载 : Apache JMeter - Download Apache JMeter 详参&#xf…

从规划到落地,数字化工厂如何破局

随着第四次工业革命的推进&#xff0c;数字化工厂解决方案已经成为制造业转型升级的必经之路。然而&#xff0c;在实际推进过程中&#xff0c;许多企业却面临着规划难以落地、投资回报率低、人才短缺等问题。如何破局&#xff0c;实现数字化工厂的顺利转型&#xff0c;成为制造…

puzzle(0414)六边形拼图

目录 六边形拼图 简单 中等 困难 六边形拼图 taptap小游戏 简单 &#xff08;3&#xff09; &#xff08;4&#xff09; 中等 &#xff08;3&#xff09; &#xff08;4&#xff09; 困难 &#xff08;2&#xff09; &#xff08;3&#xff09; &#xff08;4&#xff…

Python 程序设计入门(021)—— 循环结构程序设计(2):while 循环

Python 程序设计入门&#xff08;021&#xff09;—— 循环结构程序设计&#xff08;2&#xff09;&#xff1a;while 循环 目录 Python 程序设计入门&#xff08;021&#xff09;—— 循环结构程序设计&#xff08;2&#xff09;&#xff1a;while 循环一、while 循环的语法二…

单片机如何分散加载文件

本篇文章将通过实际操作介绍如何实现分散加载文件的方法。开发工具为&#xff1a;mdk&#xff1b;开发板&#xff1a;野火stm32f407 一、建立工程 通过实现简单的加法计算的软件算法&#xff0c;来了解分散加载image 的方法。 建立工程&#xff0c;创建文件夹以及相应的文件&am…

设计师都会用哪些在线设计工具?

在效率为王的时代&#xff0c;在线设计是设计的未来&#xff0c;为设计师提供了更节省时间、精力和成本的解决方案。在线设计工具可以通过打开浏览器使用&#xff0c;大多数操作界面比传统设计工具更简单&#xff0c;入门门槛很低。此外&#xff0c;它还为云存储提供了便利&…

通俗讲解-动量梯度下降法原理与代码实例

本站原创文章&#xff0c;转载请说明来自《老饼讲解-BP神经网络》bp.bbbdata.com 目录 一.动量梯度下降法介绍 1.1 动量梯度下降法简介与思想 1.2 动量梯度下降法的算法流程 二.动量梯度下降法代码实例 2.1 动量梯度下降法实例代码 一.动量梯度下降法介绍…

7-3 查询水果价格

分数 15 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 给定四种水果&#xff0c;分别是苹果&#xff08;apple&#xff09;、梨&#xff08;pear&#xff09;、桔子&#xff08;orange&#xff09;、葡萄&#xff08;grape&#xff09;&#xff0c;单价分别对应为3.00…

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

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

浪潮信息赵帅:多元算力时代 开源开放的OpenBMC成为服务器管理优先解

“多元算力时代下&#xff0c;大规模的异构服务器设备面临多种处理器架构、多种设备协议、不同管理芯片兼容的系统化设计挑战&#xff0c;管理固件也迎来新的变革。开源开放的OpenBMC&#xff0c;以创新的分层解耦软件架构&#xff0c;兼容不同处理器架构、算力平台和管理芯片&…

Python爬虫——scrapy_工作原理

引擎向spiders要url引擎把将要爬取的url给调度器调度器会将url生成的请求对象放入到指定的队列中从队列中出队一个请求引擎将请求交给下载器进行处理下载器发送请求获取互联网数据下载器将数据返回给引擎引擎将数据再次给到spidersspiders通过xpath解析该数据&#xff0c;得到数…

springboot集成ES

1.引入pom依赖2.application 配置3.JavaBean配置以及ES相关注解 3.1 Student实体类3.2 Teacher实体类3.3 Headmaster 实体类4. 启动类配置5.elasticsearchRestTemplate 新增 5.1 createIndex && putMapping 创建索引及映射 5.1.1 Controller层5.1.2 service层5.1.3 ser…

飞天使-jenkins进行远程linux机器修改某个文件的思路

文章目录 jenkins配置的方式jenkins中执行shell的思路 jenkins配置的方式 jenkins中执行shell的思路 下面的脚本别照抄&#xff0c;只是一个思路 ipall"$ips"# 将文本参数按行输出为变量 while IFS read -r line; doecho "$line" if [[ ! -z $line ]] &…

linux——mysql的高可用MHA

目录 一、概述 一、概念 二、组成 三、特点 四、工作原理 二、案例 三、构建MHA 一、基础环境 二、ssh免密登录 三、主从复制 master slave1 四、MHA安装 一、环境 二、安装node 三、安装manager 一、概述 一、概念 MHA&#xff08;MasterHigh Availability&a…

Spring Boot 知识集锦之actuator监控端点详解

文章目录 0.前言1.参考文档2.基础介绍默认支持的端点 3.步骤3.1. 引入依赖3.2. 配置文件3.3. 核心源码 4.示例项目5.总结 0.前言 背景&#xff1a; 一直零散的使用着Spring Boot 的各种组件和特性&#xff0c;从未系统性的学习和总结&#xff0c;本次借着这个机会搞一波。共同学…

10 - 把间隔的几个commit整理成1个

查看所有文章链接&#xff1a;&#xff08;更新中&#xff09;GIT常用场景- 目录 文章目录 把间隔的几个commit整理成1个 把间隔的几个commit整理成1个

Elisp之获取PC电池状态(二十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

BTC转移案例分析

比特币 / 地址 / 3LyBT9iuka23wgRnYS88QggNw8gC15ntTC — Blockchair 涉及金额&#xff1a;10BTC 案例背景&#xff1a;存入了一定数量的BTC&#xff0c;前几天发现钱包空了&#xff0c;里面预存的BTC丢失了 解决方案&#xff1a;跟踪交易记录&#xff0c;交易所协助查询&am…