news 2026/4/29 0:36:01

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/4/25 17:18:04

ncmdumpGUI:解锁网易云音乐ncm格式的终极指南

ncmdumpGUI&#xff1a;解锁网易云音乐ncm格式的终极指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾遇到过这样的困扰&#xff1a;从网易云音乐下…

作者头像 李华
网站建设 2026/4/24 20:50:36

WPS文档在线预览终极指南:3步快速集成Vue组件

WPS文档在线预览终极指南&#xff1a;3步快速集成Vue组件 【免费下载链接】wps-view-vue wps在线编辑、预览前端vue项目&#xff0c;基于es6 项目地址: https://gitcode.com/gh_mirrors/wp/wps-view-vue wps-view-vue是一个基于Vue.js和ES6开发的开源前端组件&#xff0…

作者头像 李华
网站建设 2026/4/28 18:12:10

突破网盘下载限制!这款神器让你告别龟速下载

突破网盘下载限制&#xff01;这款神器让你告别龟速下载 【免费下载链接】netdisk-fast-download 各类网盘直链解析, 已支持蓝奏云/奶牛快传/移动云云空间/UC网盘/小飞机盘/亿方云/123云盘等. 预览地址 https://lz.qaiu.top 项目地址: https://gitcode.com/gh_mirrors/ne/net…

作者头像 李华
网站建设 2026/4/23 20:01:39

Day 40 复习日

浙大疏锦行 用 MLP 神经网络训练&#xff0c;并且让代码更规范美观&#xff0c;用到之前讲的知识点比如类的 call 方法、模型评估、GPU 训练、模型结构可视化等。 首先&#xff0c;梳理步骤&#xff1a; 代码重构&#xff0c;模块化&#xff1a;把预处理、模型构建、训练、评…

作者头像 李华
网站建设 2026/4/18 12:48:14

Unity游戏翻译插件快速上手:完整多语言解决方案实战指南

Unity游戏翻译插件快速上手&#xff1a;完整多语言解决方案实战指南 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 想要为Unity游戏添加多语言支持吗&#xff1f;XUnity.AutoTranslator作为功能强大的Un…

作者头像 李华