当前位置: 首页 > news >正文

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(); } }
http://www.gsyq.cn/news/112075.html

相关文章:

  • BetterNCM 安装器完整使用指南:从零开始掌握插件管理
  • 阴阳师百鬼夜行效率提升终极指南:5个自动化技巧快速掌握
  • LobeChat能否实现AI律师函撰写?法律文书自动化产出
  • Video DownloadHelper 配套应用终极配置指南:告别视频下载烦恼
  • PyJWT与Django实战:从零构建现代化认证系统
  • 显卡驱动终极清理方案:Display Driver Uninstaller完整使用指南
  • LobeChat能否对接GitHub?代码仓库智能搜索与建议
  • cyh_蓝桥杯python学习系列一算法基础
  • 哔哩下载姬完整使用指南:轻松掌握B站视频高效下载技巧
  • ComfyUI-Manager插件管理完整指南:从零开始掌握AI绘画工具管理
  • 人工智能之数字生命---绘画能力的生成3
  • 如何设计吸引眼球的放假通知图片
  • TPFanCtrl2终极指南:让你的ThinkPad风扇智能又安静
  • LobeChat如何帮助初创公司快速上线AI产品原型?
  • Bypass Paywalls Clean完整使用教程:轻松解锁付费新闻的实用方案
  • 旧Mac系统升级优化焕新指南:突破官方限制的完美方案
  • PyJWT与Django集成终极指南:构建现代Web认证系统
  • 华为设备--多生成树全套配置
  • LobeChat社区治理模式探索:DAO投票决定方向
  • 为什么日本出了那么多诺贝尔奖,却感觉科技水平落后于现在的中国呢?
  • MTKClient终极指南:如何快速解锁联发科设备的完整潜力
  • BetterNCM终极配置指南:打造专属音乐体验的完整教程
  • 最新 CTF 入门实战指南:从认知到参赛的全流程解析
  • DDU工具深度解析:显卡驱动彻底清理的技术原理与实战指南
  • 招聘流程拖沓遭吐槽?HR这样做终结投递者焦虑
  • 现在数字生命已经能“看清物体的内部结构”了!
  • 3步搞定!文泉驿微米黑字体跨平台安装与美化全攻略
  • 终极GDriveDL使用指南:快速掌握Google Drive下载技巧
  • 笔记太乱?用 Memos+cpolar 打造高效私密笔记系统
  • 华为设备--链路聚合全套配置