热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++BoostAsio:I/O服务、I/O对象与网络编程详解

使用Boost.Asio进行异步数据处理的应用程序主要依赖于两个核心概念:I/O服务和I/O对象。I/O服务抽象了操作系统接口,使得异步操作能够高效地执行。I/O对象则代表了具体的网络资源,如套接字和文件描述符,通过这些对象可以实现数据的读写操作。本文详细介绍了这两个概念在Boost.Asio中的应用及其在网络编程中的重要性。

I/O 服务与I/O 对象

使用Boost的Asio进行异步处理数据的应用程序基于两个概念:


  • I/O服务
  • I/O对象

I/O服务抽象了操作系统的接口,允许第一时间进行异步数据处理,而I/O对象则初始化特定的操作。


// I/O服务
boost::asio:io_service// 用于网络发送和接收数据
boost::asio::ip::tcp::socket// 计时器
boost::asio::deadline_timer

#include
#includevoid handler1(const boost::system::error_code &ec)
{std::cout <<"5 s." <}void handler2(const boost::system::error_code &ec)
{std::cout <<"10 s." <}int main()
{//1 初始化 I/O服务boost::asio::io_service io_service;//2 初始化I/O对象timer,使用boost::posix_time进行时间处理boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));//3 该函数调用会立即返回timer1.async_wait(handler1);boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(10));timer2.async_wait(handler2);//4 启动异步处理&#xff0c;进入阻塞状态io_service.run();return 0;
}

可扩展性与多线程


用boost asio这样的库开发程序&#xff0c;与一般的C&#43;&#43;风格不同。哪些可能需要较长时间才返回的函数不再以顺序的方式来调用。不在是调用阻塞式的函数&#xff0c;boost asio是启动一个异步操作。而那些需要在操作结束后调用的函数则实现为相应的句柄。这种方法的缺点是&#xff0c;本来顺序执行的功能变得在物理上分割开来了&#xff0c;从而令相应的代码更难理解。
象 Boost asio 这样的库通常是为了令应用程序具有更高的效率。应用程序不在需要等待特定的函数执行完成&#xff0c;而可以在期间执行其它任务&#xff0c;如开始另一个需要较长时间的操作。


#include
#include
#includevoid handler1(const boost::system::error_code &ec)
{std::cout <<"5 s." <}void handler2(const boost::system::error_code &ec)
{std::cout <<"5 s." <}// 使用两个 I/O 服务
boost::asio::io_service io_service1;
boost::asio::io_service io_service2;void run1()
{io_service1.run();
}void run2()
{io_service2.run();
}int main()
{boost::asio::deadline_timer timer1(io_service1, boost::posix_time::seconds(5));timer1.async_wait(handler1);boost::asio::deadline_timer timer2(io_service2, boost::posix_time::seconds(5));timer2.async_wait(handler2);boost::thread thread1(run1);boost::thread thread2(run2);thread1.join();thread2.join();
}

这个应用程序的功能与前一个相同。在一定条件下使用多个I/O服务是有好处的&#xff0c;每个I/O服务有自己的线程&#xff0c;最好是运行在各自的处理器内核上&#xff0c;这样每一个异步操作连同它们的句柄就可以局部化执行。如果没有远端的数据或函数需要访问&#xff0c;那么每一个I/O服务就像一个小的自主应用。这里的局部和远端是指像高速缓存&#xff0c;内存页这样的资源。由于在确定优化策略之前需要对底层硬件&#xff0c;操作系统&#xff0c;编译器以及潜在的瓶颈有专门的了解&#xff0c;所以应该仅在清楚这些好处的情况下使用多个I/O服务。


网络编程

虽然 boost.asio 是一个可以异步处理任何种类数据的库&#xff0c;但是它主要被用于网络编程。这是由于&#xff0c;事实上Boost.Asio在加入其他I/O对象之前很久就已经支持网络功能了。网络功能是异步处理的一个很好的例子&#xff0c;因为通过网络进行数据传输可能会需要较长时间&#xff0c;从而不能直接获得确认或错误条件。

#include
#include
#include
#include boost::asio::io_service io_service;
// 域名解析器
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::socket sock(io_service);
boost::array buffer; void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{ if (!ec) { std::cout <} void connect_handler(const boost::system::error_code &ec)
{ if (!ec) { boost::asio::write(sock, boost::asio::buffer("GET / HTTP 1.1\r\nHost: graycatya.com\r\n\r\n")); sock.async_read_some(boost::asio::buffer(buffer), read_handler); }
} void resolve_handler(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator it)
{ if (!ec) { sock.async_connect(*it, connect_handler);}
} int main()
{ boost::asio::ip::tcp::resolver::query query("www.graycatya.com", "80"); resolver.async_resolve(query, resolve_handler); io_service.run();
}

  • boost::asio::ip::tcp::resolver

域名解析也是一个需要连接到互联网的过程。 有些专门的PC&#xff0c;被称为DNS服务器&#xff0c;其作用就象是电话本&#xff0c;它知晓哪个IP地址被赋给了哪台PC。 由于这个过程本身的透明的&#xff0c;只要明白其背后的概念以及为何需要。


  • async_resolve

一旦域名解析成功或被某个错误中断&#xff0c;resolve_handler() 函数就会被调用。

*** 软件执行流程 ***


  1. 应用创建一个类型(bost::asio::ip::tcp::resolver::query)对象query&#xff0c;表示一个查询&#xff0c;这个查询被传递给async_resolve()方法以解析该域名。
  2. 当域名解析完成后&#xff0c;resolve_handler()被调用 访问I/O对象sock,用由迭代器it所提供的解析后地址创建一个连接&#xff0c;如果解析成功&#xff0c;则存有错误条件的对象ec被设为0&#xff0c;只有在这种情况下&#xff0c;才会相应地访问socket以创建连接。服务器地地址是通过类型为boost::asio::ip::tcp::resolver::iterator提供。
  3. 调用了 async_connect()方法之后&#xff0c;connect_handler()会被自动调用。在该句柄地内部&#xff0c;会访问ec对象以检查连接是否已建立。如果连接是有效的&#xff0c;则对相应的socket调用async_read_some()方法&#xff0c;启动读数据操作。为保存接收到的数据&#xff0c;要提供一个缓冲区作为第一个参数。在以下例子中&#xff0c;缓冲区类型是boost::array。
  4. 每当有一个或多个字节被接收并保存至缓冲区时&#xff0c;read_handler()函数就会被调用。准确的字节数通过std::size_t 类型的参数 bytes_transferred 给出。同样的规则&#xff0c;该句柄应该首先看看参数ec以检查有没有接收错误。如果是成功接收&#xff0c;则将数据写出至标准输出流。
    注意&#xff1a;read_handler() 在将数据写出至std::cout之后&#xff0c;会再次调用async_read_some()方法。这是必需的&#xff0c;因为无法保证仅在一次异步操作中就可以接收到整个网页。async_read_some() 和 read_handler() 的交替调用只有当连接被破坏时才中止&#xff0c;如当web服务器已经传送完整个网页时。这种情况下&#xff0c;在read_handler() 内部将报告一个错误&#xff0c;以防止进一步将数据输出至标准输出流&#xff0c;以及进一步对该socket调用async_read() 方法。

推荐阅读
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 本文详细介绍了如何在云服务器上配置Nginx、Tomcat、JDK和MySQL。涵盖从下载、安装到配置的完整步骤,帮助读者快速搭建Java Web开发环境。 ... [详细]
  • 本文介绍了如何利用Python进行批量图片尺寸调整,包括放大和等比例缩放。文中提供了详细的代码示例,并解释了每个步骤的具体实现方法。 ... [详细]
  • 本文介绍如何利用栈数据结构在C++中判断字符串中的括号是否匹配。通过顺序栈和链栈两种方式实现,并详细解释了算法的核心思想和具体实现步骤。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • 深入解析ESFramework中的AgileTcp组件
    本文详细介绍了ESFramework框架中AgileTcp组件的设计与实现。AgileTcp是ESFramework提供的ITcp接口的高效实现,旨在优化TCP通信的性能和结构清晰度。 ... [详细]
author-avatar
陌城花开2010
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有