news 2026/4/23 21:48:18

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/22 17:51:42

Linux基本指令入门:从看不懂到熟练使用

目录 前言&#xff1a; 一、前置知识&#xff1a;先搞懂 Linux 终端与命令格式 二、必学基础指令 2.1 定位当前位置&#xff1a;pwd 指令 2.2 浏览目录内容&#xff1a;ls 指令 2.3 切换工作目录&#xff1a;cd 指令 2.4 创建空文件&#xff1a;touch 指令 2.5 创建目录…

作者头像 李华
网站建设 2026/4/22 4:04:09

Java:写给学弟学妹的一封信——我们为什么要深入理解这门语言

Java&#xff1a;写给学弟学妹的一封信——我们为什么要深入理解这门语言凌晨三点&#xff0c;屏幕的光还亮着。这次的报错信息是 NullPointerException——又是它。这已经是本周第三次遇到这个“老朋友”了。如果你也在学习Java的路上挣扎&#xff0c;请相信&#xff0c;我们都…

作者头像 李华
网站建设 2026/4/17 7:07:18

C# 從入門到精通:全方位掌握現代程式語言

C# 從入門到精通&#xff1a;全方位掌握現代程式語言第一部分&#xff1a;C# 入門基礎1.1 C# 概述與發展歷程C#&#xff08;發音為 "C Sharp"&#xff09;是由微軟在 2000 年推出的現代化、物件導向的程式語言。它結合了 C 的強大功能與 Java 的簡潔性&#xff0c;並…

作者头像 李华
网站建设 2026/4/23 15:30:51

Flutter 开发工具链详解

欢迎大家加入开源鸿蒙跨平台开发者社区&#xff0c;一起共建开源鸿蒙跨平台生态。 # Flutter 开发工具链详解 Flutter 是一个由 Google 开发的跨平台移动应用开发框架&#xff0c;其完整的工具链涵盖了从开发环境搭建到应用发布的整个生命周期。以下将详细介绍 Flutter 的核心…

作者头像 李华
网站建设 2026/4/19 17:45:57

Video DownloadHelper 配套应用终极配置指南:告别视频下载烦恼

Video DownloadHelper 配套应用终极配置指南&#xff1a;告别视频下载烦恼 【免费下载链接】vdhcoapp Companion application for Video DownloadHelper browser add-on 项目地址: https://gitcode.com/gh_mirrors/vd/vdhcoapp 还在为浏览器视频下载功能受限而苦恼吗&am…

作者头像 李华
网站建设 2026/4/18 5:01:46

TranslucentTB深度汉化指南:从原理到实战的系统美化艺术

TranslucentTB深度汉化指南&#xff1a;从原理到实战的系统美化艺术 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 对于Windows系统美化…

作者头像 李华