news 2026/6/23 23:11:39

C++ asio网络编程(2) buffer同步读写

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ asio网络编程(2) buffer同步读写

一、buffer是什么

任何网络库都有提供buffer的数据结构,所谓buffer就是接收和发送数据时缓存数据的结构。
boost::asio提供了asio::mutable_buffer 和 asio::const_buffer这两个结构,他们是一段连续的空间,首字节存储了后续数据的长度。
asio::mutable_buffer用于写服务,asio::const_buffer用于读服务。但是这两个结构都没有被asio的api直接使用。
对于api的buffer参数,asio提出了MutableBufferSequence和ConstBufferSequence概念,他们是由多个asio::mutable_buffer和asio::const_buffer组成的。也就是说boost::asio为了节省空间,将一部分连续的空间组合起来,作为参数交给api使用。
我们可以理解为MutableBufferSequence的数据结构为std::vector<asio::mutable_buffer>

结构如下:

每隔vector存储的都是mutable_buffer的地址,每个mutable_buffer的第一个字节表示数据的长度,后面跟着数据内容。
这么复杂的结构交给用户使用并不合适,所以asio提出了buffer()函数,该函数接收多种形式的字节流,该函数返回asio::mutable_buffers_1 o或者asio::const_buffers_1结构的对象。
如果传递给buffer()的参数是一个只读类型,则函数返回asio::const_buffers_1 类型对象。
如果传递给buffer()的参数是一个可写类型,则返回asio::mutable_buffers_1 类型对象。
asio::const_buffers_1和asio::mutable_buffers_1是asio::mutable_buffer和asio::const_buffer的适配器,提供了符合MutableBufferSequence和ConstBufferSequence概念的接口,所以他们可以作为boost::asio的api函数的参数使用。

简单概括一下,我们可以用buffer()函数生成我们要用的缓存存储数据。
比如boost的发送接口send要求的参数为ConstBufferSequence类型

//ConstBufferSequence 常量缓冲区序列类型 template<typename ConstBufferSequence> std::size_t send(const ConstBufferSequence & buffers);

1.利用buffer发送数据

void use_const_buffer() { std::string buf = "hello boost"; //转换为const_buffer类型 buf.c_str()为字符串首地址,buf.length()字符串的长度 asio::const_buffer asio_buf(buf.c_str(), buf.length()); //构建缓冲区序列(vector 容器存储多个 const_buffer) std::vector<asio::const_buffer> buffers_sequence; // // 将单个 const_buffer 添加到缓冲区序列中 // 实际场景中可添加多个不同的 const_buffer,发送时会按顺序拼接所有缓冲区数据 buffers_sequence.push_back(asio_buf); }

下面这种方法可以直接用buffer函数转化为send需要的参数类型

void use_buffer_str() { asio::const_buffer output_buf = asio::buffer("hello world"); }

我们也可以将数组转化为send接受的类型

void use_buffer_array() { const size_t BUF_SIZE_BYTES = 20; std::unique_ptr<char[]>buf(new char[BUF_SIZE_BYTES]); auto input_buf = asio::buffer(static_cast<void*>(buf.get()), BUF_SIZE_BYTES); }

二、asio socket同步读写

同步写

1.同步写write_some

boost::asio提供了几种同步写的api,write_some可以每次向指定的空间写入固定的字节数,如果写缓冲区满了,就只写一部分,返回写入的字节数。

void wirte_to_socket(asio::ip::tcp::socket& sock) { std::string buf = "Hello world"; //total_bytes_w是已发送的字节数 std::size_t total_bytes_w = 0; //循环发送 //write_som 返回每次写入的字节数 while (total_bytes_w != buf.length()) { total_bytes_w += sock.write_some(asio::buffer(buf.c_str() + total_bytes_w, buf.length() - total_bytes_w)); } }

2.同步写send

write_some使用起来比较麻烦,需要多次调用,asio提供了send函数。send函数会一次性将buffer中的内容发送给对端,如果有部分字节因为发送缓冲区满无法发送,则阻塞等待,直到发送缓冲区可用,则继续发送完成。

int send_data_by_send() { std::string raw_ip_address = "192.168.3.11"; unsigned short port_num = 6666; try { asio::ip::tcp::endpoint ep(asio::ip::make_address(raw_ip_address), port_num); asio::io_context ioc; asio::ip::tcp::socket sock(ioc, ep.protocol()); sock.connect(ep); std::string buf = "Hello world"; int send_length = sock.send(buf.c_str(), buf.length()); if (send_length <= 0) { return 0; } } catch (system::system_error& e) { std::cout << "Error code = " << e.code() << ". Message: " << e.what(); return e.code().value(); } }

3.同步写write

类似send方法,asio还提供了一个write函数,可以一次性将所有数据发送给对端,如果发送缓冲区满了则阻塞,直到发送缓冲区可用,将数据发送完成。

int send_data_by_write() { std::string raw_ip_address = "192.168.3.11"; unsigned short port_num = 6666; try { asio::ip::tcp::endpoint ep(asio::ip::make_address(raw_ip_address), port_num); asio::io_context ioc; asio::ip::tcp::socket sock(ioc, ep.protocol()); sock.connect(ep); std::string buf = "Hello world"; int send_length = asio::write(sock,asio::buffer(buf.c_str(), buf.length())); if (send_length <= 0) { return 0; } } catch (system::system_error& e) { std::cout << "Error code = " << e.code() << ". Message: " << e.what(); return e.code().value(); } }

同步读

1.同步读read_some

同步读和同步写类似,提供了读取指定字节数的接口read_some

std::string read_from_socket(asio::ip::tcp::socket& sock) { const unsigned char MESSAGE_SIZE = 7; char buf[MESSAGE_SIZE]; std::size_t total_bytes_read = 0; while (total_bytes_read != MESSAGE_SIZE) { total_bytes_read += sock.read_some(asio::buffer(buf + total_bytes_read, MESSAGE_SIZE - total_bytes_read)); } return std::string(buf, total_bytes_read); } int read_data_byread_some() { std::string raw_ip_address = "192.168.3.11"; unsigned short port_num = 6666; try { asio::ip::tcp::endpoint ep(asio::ip::make_address(raw_ip_address), port_num); asio::io_context ioc; asio::ip::tcp::socket sock(ioc, ep.protocol()); sock.connect(ep); read_from_socket(sock); } catch (system::system_error& e) { std::cout << "Error code = " << e.code() << ". Message: " << e.what(); return e.code().value(); } }

2.同步读receive

可以一次性同步接收对方发送的数据

int read_data_by_recevie() { std::string raw_ip_address = "192.168.3.11"; unsigned short port_num = 6666; try { asio::ip::tcp::endpoint ep(asio::ip::make_address(raw_ip_address), port_num); asio::io_context ioc; asio::ip::tcp::socket sock(ioc, ep.protocol()); sock.connect(ep); const unsigned char Buff_SIZE = 7; char buff_recevie[Buff_SIZE]; int receive_length = sock.receive(asio::buffer(buff_recevie, Buff_SIZE)); if (receive_length <= 0) { std::cout << "receive failed" << std::endl; } } catch (system::system_error& e) { std::cout << "Error code = " << e.code() << ". Message: " << e.what(); return e.code().value(); } }

3.同步读read

可以一次性同步读取对方发送的数据

int read_data_by_read() { std::string raw_ip_address = "192.168.3.11"; unsigned short port_num = 6666; try { asio::ip::tcp::endpoint ep(asio::ip::make_address(raw_ip_address), port_num); asio::io_context ioc; asio::ip::tcp::socket sock(ioc, ep.protocol()); sock.connect(ep); const unsigned char Buff_SIZE = 7; char buff_recevie[Buff_SIZE]; int receive_length = asio::read(sock,asio::buffer(buff_recevie, Buff_SIZE)); if (receive_length <= 0) { std::cout << "receive failed" << std::endl; } } catch (system::system_error& e) { std::cout << "Error code = " << e.code() << ". Message: " << e.what(); return e.code().value(); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 16:19:37

MusicFree插件完全指南:解锁个性化音乐体验的终极教程

想要让音乐播放器真正变成你的专属音乐管家吗&#xff1f;MusicFree插件系统就是实现个性化音乐体验的关键&#xff01;通过插件扩展功能&#xff0c;你可以轻松获取各大平台的音乐资源、享受精准歌词服务、打造专属音乐库。本指南将带你从零开始&#xff0c;快速掌握插件安装、…

作者头像 李华
网站建设 2026/6/23 22:11:21

显卡驱动终极清理方案:Display Driver Uninstaller完整使用指南

显卡驱动终极清理方案&#xff1a;Display Driver Uninstaller完整使用指南 【免费下载链接】display-drivers-uninstaller Display Driver Uninstaller (DDU) a driver removal utility / cleaner utility 项目地址: https://gitcode.com/gh_mirrors/di/display-drivers-uni…

作者头像 李华
网站建设 2026/6/23 22:11:19

5分钟从入门到精通!PandaWiki:零代码小白的AI编程助手

还在为编程查资料抓狂&#xff1f;5 分钟解锁 PandaWiki&#xff0c;AI 帮你搞定 80% 编程难题作为编程新手&#xff0c;是不是总被这些问题困住&#xff1a;想查 API 用法翻遍官网找不到重点&#xff0c;遇到报错搜半天全是零散答案&#xff0c;写技术文档卡壳半天憋不出字&am…

作者头像 李华
网站建设 2026/6/23 13:02:01

基于JAVA的图书馆图书资源检索借阅系统

目录 已开发项目效果实现截图开发技术系统开发工具&#xff1a; 核心代码参考示例1.建立用户稀疏矩阵&#xff0c;用于用户相似度计算【相似度矩阵】2.计算目标用户与其他用户的相似度系统测试总结源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&am…

作者头像 李华
网站建设 2026/6/22 20:14:24

原神自动化脚本7大实用技巧:新手也能快速上手的完整指南

原神自动化脚本7大实用技巧&#xff1a;新手也能快速上手的完整指南 【免费下载链接】better-genshin-impact &#x1f368;BetterGI 更好的原神 - 自动拾取 | 自动剧情 | 全自动钓鱼(AI) | 全自动七圣召唤 | 自动伐木 | 自动派遣 | 一键强化 - UI Automation Testing Tools F…

作者头像 李华
网站建设 2026/6/22 19:16:21

基于Java的奖学金评定评优系统的设计与实现

目录已开发项目效果实现截图开发技术系统开发工具&#xff1a;核心代码参考示例1.建立用户稀疏矩阵&#xff0c;用于用户相似度计算【相似度矩阵】2.计算目标用户与其他用户的相似度系统测试总结源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&…

作者头像 李华