c++网络编程:Boost.asio源码剖析

news2024/12/23 5:42:21

1、前言

Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一。Boost库由C++标准委员会库工作组成员发起,其中有些内容有望成为下一代C++标准库内容。在C++社区中影响甚大,是不折不扣的“准”标准库。

boost.asio是Boost库中非常著名的I/O组件,是用于网络和低层IO编程的跨平台C++库,为开发者提供了C++环境下稳定的异步模型。其在性能、移植性、扩展性等方面均为人称道,甚至被很多业内人士称为“网络神器”。asio是目前唯一有希望进入C++标准库以弥补标准库在网络方面的缺失的C++网络库,因此对asio的学习在某种意义上可以说是学习C++网络编程的必修课。

当前网络上从用户角度介绍asio的文献很多也很完善,所以本文决定另辟蹊径,从asio源码角度出发,由内而外、深入浅出地剖析asio的架构和设计理念,将asio的一切秘密呈现在读者眼前。

本文适合已有较完善的C++基础知识、具备一定程度的泛型技术和面向对象技术、并对boost.asio有一定的了解的读者。

2、架构浅析

先来看一下asio的0层的组件图。

​(图1.0)

io_object是I/O对象的集合,其中包含大家所熟悉的socket、deadline_timer等对象,主要功能是提供接口给用户使用。

services服务是逻辑功能的实现者,其中包含提供定时功能的deadline_timer_service、提供socket相关功能的win_iocp_socket_service(windows平台)/reactive_socket_service(其他平台)、作为io_service功能的真正实现者win_iocp_io_service(windows平台)/task_io_service(其他平台)等等服务。

"Asio核心组件"在这一层中可以理解为就是io_service,它通过关联的类service_registry将实现具体功能所需的服务组合起来,再由io_object提供接口给用户使用。

这三大组件构成了asio的核心架构,asio的一切都是以此为根基衍生扩展出来的。

让我们将图1.0进一步细化:

​(图1.1)

“Asio核心组件”细化为4个类:io_service,service_registry,service,service_base。其中,service_registry负责管理所有服务,使用延迟创建技术,在真正使用服务对象的时候才创建服务对象,并以单链表的方式管理,但只能增不能删,直到service_registry析构时才会释放其管理的服务对象。service是io_service的类中类,是一个虚基类,所有由service_registry管理的服务都必须从service派生。service_base是service的直接派生类,是services继承体系的第二级,组合了service_id<Type>,目前asio中所有服务均继承与service_base。

“I/O对象”细化为basic_io_object及其派生类。basic_io_object是所有I/O对象的基类,提供I/O对象与其对应服务的联系。 再将图1.1进一步细化(关注网络I/O方面的一些类,其他方面的类未画出):

​(图1.2)

io_service的真正逻辑实现封装在内部桥接的类io_service_impl中,io_service_impl是一个typedef(在windows平台下是win_iocp_io_service,其他平台下是task_io_service)。io_service_impl就是一个继承于service_base的服务,在io_service初始化也就是其关联类service_registry初始化时被创建,再由io_service持有其引用。

从图中可以看到,继承于service_base的服务有:

strand_service:提供串行化多线程调用的功能

deadline_timer_service:提供定时器功能

stream_socket_service:提供流式socket相关功能

datagram_socket_service:提供报文式socket相关功能

seq_packet_socket_service:提供seq_packet socket相关功能

raw_socket_service:提供原始套接字相关功能

socket_acceptor_service:提供端口监听和接受客户端连接相关功能

这些服务都是幕后英雄,对于用户而言是感知不到的,用户使用的都是其对应的I/O对象。

这些服务对应的I/O对象是:

io_service::strand

basic_deadline_timer

basic_stream_socket

basic_datagram_socket

basic_seq_packet_socket

basic_raw_socket

basic_socket_acceptor

除此之外,asio中还有串口通信、信号处理等功能,在此不再一一赘述。

相关视频推荐

boost.asio是什么?解决了网络编程中哪些痛点?

手把手带你看 mmorpg 开源框架的网络模块封装

8个方面讲解io_uring,重塑对异步io的理解

免费学习地址:c/c++ linux服务器开发/后台架构师

需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

3、流程分析

3.1常见流程分析之一(Tcp异步连接)

我们用一个简单的demo分析Tcp异步连接的流程:

 1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 
 4 // 异步连接回调函数
 5 void on_connect(boost::system::error_code ec)
 6 {
 7     if (ec)  // 连接失败, 输出错误码
 8         std::cout << "async connect error:" << ec.message() << std::endl;
 9     else  // 连接成功
10         std::cout << "async connect ok!" << std::endl;
11 }
12 
13 int main()
14 {
15     boost::asio::io_service ios;  // 创建io_service对象
16     boost::asio::ip::tcp::endpoint addr(
17         boost::asio::ip::address::from_string("127.0.0.1"), 12345);  // server端地址
18     boost::asio::ip::tcp::socket conn_socket(ios);  // 创建tcp协议的socket对象
19     conn_socket.async_connect(addr, &on_connect);  // 发起异步连接请求
20     ios.run();  // 调用io_service::run, 等待异步操作结果
21 
22     std::cin.get();
23     return 0;
24 }

这段代码中的异步连接请求在asio源码中的序列图如下:

其中,basic_socket是个模板类,tcp协议中的socket的定义如下:

typedef basic_socket<tcp> socket;

reactor的定义如下:

      #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
            typedef class null_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_IOCP)
            typedef class select_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_EPOLL)
            typedef class epoll_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_KQUEUE)
            typedef class kqueue_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_DEV_POLL)
            typedef class dev_poll_reactor reactor;
      #else
            typedef class select_reactor reactor;
      #endif

在这个序列图中最值得注意的一点是:在windows平台下,异步连接请求不是由Iocp处理的,而是由select模型处理的,这是与异步读写数据最大的不同之处。

3.2常见流程分析之二(Tcp异步接受连接)

我们用一个简单的demo分析Tcp异步连接的流程:

 1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 
 5 // 异步连接回调函数
 6 void on_accept(boost::system::error_code ec, boost::asio::ip::tcp::socket * socket_ptr)
 7 {
 8     if (ec)  // 连接失败, 输出错误码
 9         std::cout << "async accept error:" << ec.message() << std::endl;
10     else  // 连接成功
11         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
12 
13     // 断开连接, 释放资源.
14     socket_ptr->close(), delete socket_ptr;
15 }
16 
17 int main()
18 {
19     boost::asio::io_service ios;  // 创建io_service对象
20     boost::asio::ip::tcp::endpoint addr(
21         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
22     boost::asio::ip::tcp::acceptor acceptor(ios, addr, false);  // 创建acceptor对象
23     boost::asio::ip::tcp::socket * socket_ptr = new boost::asio::ip::tcp::socket(ios);
24     acceptor.async_accept(*socket_ptr
25         , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr));  // 调用异步accept请求
26     ios.run();  // 调用io_service::run, 等待异步操作结果
27 
28     std::cin.get();
29     return 0;
30 }

这段代码中的异步连接请求在asio源码中的序列图如下:

3.3常见流程分析之三(Tcp异步读写数据)

我们依然以上一节的例子为基础,扩展一个简单的demo分析Tcp异步读写数据的流程:

 1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 #include <boost/shared_ptr.hpp>
 5 #include <boost/array.hpp>
 6 
 7 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
 8 typedef boost::array<char, 128> buffer_t;
 9 typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
10 
11 // 异步读数据回调函数
12 void on_read(boost::system::error_code ec
13     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
14 {
15     if (ec)
16         std::cout << "async write error:" << ec.message() << std::endl;
17     else
18     {
19         std::cout << "async read size:" << len;
20         std::cout << " info:" << std::string((char*)buffer_ptr->begin(), len) << std::endl;
21 
22         // auto release socket and buffer.
23     }
24 }
25 
26 // 异步写数据回调函数
27 void on_write(boost::system::error_code ec
28     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
29 {
30     if (ec)
31         std::cout << "async write error:" << ec.message() << std::endl;
32     else
33     {
34         std::cout << "async write size:" << len << std::endl;
35         socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
36             , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
37                 , socket_ptr, buffer_ptr));
38     }
39 }
40 
41 // 异步连接回调函数
42 void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
43 {
44     if (ec)  // 连接失败, 输出错误码
45     {
46         std::cout << "async accept error:" << ec.message() << std::endl;
47     }
48     else  // 连接成功
49     {
50         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
51         buffer_ptr_t buffer_ptr(new buffer_t);
52         strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
53         socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
54             , boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
55                 , socket_ptr, buffer_ptr));
56     }
57 }
58 
59 int main()
60 {
61     boost::asio::io_service ios;  // 创建io_service对象
62     boost::asio::ip::tcp::endpoint addr(
63         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
64     boost::asio::ip::tcp::acceptor acceptor(ios, addr, false);  // 创建acceptor对象
65     socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
66     acceptor.async_accept(*socket_ptr
67         , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr));  // 调用异步accept请求
68     ios.run();  // 调用io_service::run, 等待异步操作结果
69 
70     std::cout << "press enter key...";
71     std::cin.get();
72     return 0;
73 }  

这段代码中的异步连接请求在asio源码中的序列图如下:

3.4常见流程分析之四(Tcp强制关闭连接)

我们依然以上一节的例子为基础,扩展一个简单的demo分析Tcp强制关闭连接的流程:

 1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 #include <boost/shared_ptr.hpp>
 5 #include <boost/array.hpp>
 6 
 7 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
 8 typedef boost::array<char, 128> buffer_t;
 9 typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
10 
11 // 异步读数据回调函数
12 void on_read(boost::system::error_code ec
13     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
14 {
15     if (ec)  // 连接失败, 输出错误码
16     {
17         std::cout << "async read error:" << ec.message() << std::endl;
18     }
19 }
20 
21 // 异步写数据回调函数
22 void on_write(boost::system::error_code ec
23     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
24 {
25     if (ec)  // 连接失败, 输出错误码
26     {
27         std::cout << "async write error:" << ec.message() << std::endl;
28     }
29 }
30 
31 // 异步连接回调函数
32 void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
33 {
34     if (ec)  // 连接失败, 输出错误码
35     {
36         std::cout << "async accept error:" << ec.message() << std::endl;
37     }
38     else  // 连接成功
39     {
40         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
41 
42         {
43             buffer_ptr_t buffer_ptr(new buffer_t);
44             strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
45             socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
46                 , boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
47                 , socket_ptr, buffer_ptr));
48         }
49 
50         {
51             buffer_ptr_t buffer_ptr(new buffer_t);
52             socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
53                 , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
54                 , socket_ptr, buffer_ptr));
55         }
56 
57         /// 强制关闭连接
58         socket_ptr->close(ec);
59         if (ec)
60             std::cout << "close error:" << ec.message() << std::endl;
61     }
62 }
63 
64 int main()
65 {
66     boost::asio::io_service ios;  // 创建io_service对象
67     boost::asio::ip::tcp::endpoint addr(
68         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
69     boost::asio::ip::tcp::acceptor acceptor(ios, addr, false);  // 创建acceptor对象
70     socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
71     acceptor.async_accept(*socket_ptr
72         , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr));  // 调用异步accept请求
73     socket_ptr.reset();
74     ios.run();  // 调用io_service::run, 等待异步操作结果
75 
76     std::cout << "press enter key...";
77     std::cin.get();
78     return 0;
79 } 

这个例子中,接受到客户端的连接后,立即发起异步读请求和异步写请求,然后立即强制关闭socket。

其中,强制关闭socket的请求在asio源码中的序列图如下:

3.5常见流程分析之五(Tcp优雅地关闭连接)

我们依然以第三节的例子为基础,扩展一个简单的demo分析Tcp优雅地关闭连接的流程:

 1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 #include <boost/shared_ptr.hpp>
 5 #include <boost/array.hpp>
 6 
 7 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
 8 typedef boost::array<char, 32> buffer_t;
 9 typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
10 
11 
12 // 异步读数据回调函数
13 void on_read(boost::system::error_code ec
14     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
15 {
16     static int si = 0;
17     if (ec)  // 连接失败, 输出错误码
18     {
19         std::cout << "async read(" << si++ << ") error:" << ec.message() << std::endl;
20         socket_ptr->shutdown(boost::asio::socket_base::shutdown_receive, ec);
21         socket_ptr->close(ec);
22         if (ec)
23             std::cout << "close error:" << ec.message() << std::endl;
24     }
25     else
26     {
27         std::cout << "read(" << si++ << ") len:" << len << std::endl;
28 
29         socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
30             , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
31             , socket_ptr, buffer_ptr));
32     }
33 }
34 
35 // 异步写数据回调函数
36 void on_write(boost::system::error_code ec
37     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
38 {
39     if (ec)  // 连接失败, 输出错误码
40     {
41         std::cout << "async write error:" << ec.message() << std::endl;
42     }
43     else
44     {
45         /// 优雅地关闭连接
46         socket_ptr->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
47         if (ec)
48             std::cout << "shutdown send error:" << ec.message() << std::endl;
49     }
50 }
51 
52 // 异步连接回调函数
53 void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
54 {
55     if (ec)  // 连接失败, 输出错误码
56     {
57         std::cout << "async accept error:" << ec.message() << std::endl;
58     }
59     else  // 连接成功
60     {
61         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
62 
63         {
64             buffer_ptr_t buffer_ptr(new buffer_t);
65             socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
66                 , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
67                 , socket_ptr, buffer_ptr));
68         }
69 
70         {
71             buffer_ptr_t buffer_ptr(new buffer_t);
72             strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
73             socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
74                 , boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
75                 , socket_ptr, buffer_ptr));
76         }
77     }
78 }
79 
80 int main()
81 { 
82     boost::asio::io_service ios;  // 创建io_service对象
83     boost::asio::ip::tcp::endpoint addr(
84         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
85     boost::asio::ip::tcp::acceptor acceptor(ios, addr, false);  // 创建acceptor对象
86     socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
87     acceptor.async_accept(*socket_ptr
88         , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr));  // 调用异步accept请求
89     socket_ptr.reset();
90     ios.run();  // 调用io_service::run, 等待异步操作结果
91 
92     std::cout << "press enter key...";
93     std::cin.get();
94     return 0;
95 }

这个例子中,接收到客户端的连接并向客户端发送数据以后,先关闭socket的发送通道,然后等待socket接收缓冲区中的数据全部read出来以后,再关闭socket的接收通道。此时,socket的接收和发送通道均以关闭,任何进程都无法使用此socket收发数据,但其所占用的系统资源并未释放,底层发送缓冲区中的数据也不保证已全部发出,需要在此之后执行close操作以便释放系统资源。

若在释放系统资源前希望底层发送缓冲区中的数据依然可以发出,则需在socket的linger属性中设置一个等待时间,以便有时间等待发送缓冲区中的数据发送完毕。但linger中的值绝对不是越大越好,这是因为其原理是操作系统帮忙保留socket的资源以等待其发送缓冲区中的数据发送完毕,如果远端socket的一直未能接收数据便会导致本地socket一直等待下去,这对系统资源是极大的浪费。因此,在需要处理大量连接的服务端,linger的值一定不可过大。

4、ASIO中的泛型概念(CONCEPTS)

4.1Protocol(通信协议)

Protocol,是asio在网络编程方面最重要的一个concept。在第一章中的levelX类图中可以看到,所有提供网络相关功能的服务和I/O对象都需要Protocol来确定一些细节。

Protocol的约束摘要如下:

 1 class protocol
 2 {
 3 public:
 4   /// Obtain an identifier for the type of the protocol.
 5   int type() const;
 6 
 7   /// Obtain an identifier for the protocol.
 8   int protocol() const;
 9 
10   /// Obtain an identifier for the protocol family.
11   int family() const;
12 
13   typedef ... endpoint;
14   typedef ... socket; 
15 };

符合Protocol约束的类需要提供type/protocol/family三个接口,分别返回协议类型/协议枚举/协议组枚举;还需要提供两个类型定义endpoint/socket,分别表示通信协议一方的地址/继承于asio::basic_socket的类型。

目前,asio中符合Protocol约束的类有:stream_protocol,datagram_protocol,raw_protocol,seq_packet_protocol;

既符合Protocol约束,同时又符合InternetProtocol约束的类有:tcp(TCP协议),udp(UDP协议),icmp(ICMP协议)。

4.2InternetProtocol(网络通信协议)

InternetProtocol,是Protocol的约束超集,在Protocol约束的基础上添加了几个新的约束。

InternetProtocol的约束摘要如下:

 1 class InternetProtocol
 2 {
 3 public:
 4   /// Construct to represent the IPv4 internet protocol.
 5   static InternetProtocol v4();
 6 
 7   /// Construct to represent the IPv6 internet protocol.
 8   static InternetProtocol v6();
 9 
10   /// Obtain an identifier for the type of the protocol.
11   int type() const;
12 
13   /// Obtain an identifier for the protocol.
14   int protocol() const;
15 
16   /// Obtain an identifier for the protocol family.
17   int family() const;
18 
19   typedef ... endpoint;
20   typedef ... socket; 
21   typedef ... resolver;
22 };

其中,type/protocol/family接口和endpoint/socket类型定义都是属于Protocol约束的部分,在此不再赘述。InternetProtocol相对于Protocol新增的约束有:v4/v6两个静态接口,分别返回IPv4/IPv6版本的网络通信协议对象;类型定义resolver,表示继承于basic_resolver的类型。

4.3ConstBuffer(不可变缓冲区),ConstBufferSequence(不可变缓冲区序列),MutableBuffer(可变缓冲区),MutableBufferSequence(可变缓冲区序列)

ConstBuffer和MutableBuffer是asio中各种组件通用的缓冲区适配器concept,在asio中以const_buffer和mutable_buffer两个类实现。

ConstBuffer和MutableBuffer的约束摘要如下:

 1 class ConstBuffer
 2 {
 3 private:
 4   friend void const* boost::asio::detail::buffer_cast_helper(const ConstBuffer& b);
 5   friend std::size_t boost::asio::detail::buffer_size_helper(const ConstBuffer& b);
 6 };
 7 
 8 class MutableBuffer
 9 {
10 private:
11   friend void* boost::asio::detail::buffer_cast_helper(const MutableBuffer& b);
12   friend std::size_t boost::asio::detail::buffer_size_helper(const MutableBuffer& b);
13 };

只需能通过buffer_cast_helper和buffer_size_helper这两个自由函数获取缓冲区首地址指针和缓冲区长度即可。这两个concept没有什么扩展的必要,因此asio中并未显式地提及,在后文中我们直接以他们当前的实现const_buffer和mutable_buffer这两个类替代。

ConstBufferSequence和MutableBufferSequence是const_buffer和mutable_buffer的容器约束。它们的约束摘要如下:

 1 class ConstBufferSequence
 2 {
 3 public:
 4     typedef const_buffer value_type;
 5     typedef ... const_iterator;
 6 
 7     const_iterator begin() const;
 8     const_iterator end() const;
 9 };
10 
11 class MutableBufferSequence
12 {
13 public:
14     typedef mutable_buffer value_type;
15     typedef ... const_iterator;
16 
17     const_iterator begin() const;
18     const_iterator end() const;
19 };

ConstBufferSequence和MutableBufferSequence只需提供begin/end两个接口,返回相应的迭代器即可。

asio中,提供了const_buffer_1和mutable_buffer_1两个类,可以方便地将单个的const_buffer和mutable_buffer封装为容器外观,使其符合ConstBufferSequence和MutableBufferSequence约束。

4.4Stream(流),AsyncReadStream(支持异步读操作的流),AsyncWriteStream(支持异步写操作的流),SyncReadStream(支持同步写操作的流),SyncWriteStream(支持同步写操作的流)

Stream,就是大家耳熟能详的“流”。

AsyncReadStream,AsyncWriteStream,SyncReadStream,SyncWriteStream四种concept是Stream的子集,在流的基础上添加一些接口。

Stream的约束摘要如下:

1 class Stream
2 {
3 public:
4     void close();
5     boost::system::error_code close(boost::system::error_code& ec);
6 };

Stream的约束非常简单,只需要两个用于关闭流的close接口。

AsyncReadStream的约束摘要如下:

 1 class AsyncReadStream
 2 {
 3 public:
 4     template <typename MutableBufferSequence, typename ReadHandler>
 5     void async_read_some(const MutableBufferSequence& buffers,
 6                 BOOST_ASIO_MOVE_ARG(ReadHandler) handler);
 7 
 8     void close();
 9     boost::system::error_code close(boost::system::error_code& ec);
10 };

AsyncReadStream在Stream的基础上增加了一个异步读数据的接口async_read_some,第一个参数buffers是一个符合MutableBufferSequence约束的对象,第二个参数是异步操作的回调函数。

AsyncWriteStream的约束摘要如下:

 1 class AsyncWriteStream
 2 {
 3 public:
 4     template <typename ConstBufferSequence, typename WriteHandler>
 5     void async_write_some(const ConstBufferSequence& buffers,
 6                 BOOST_ASIO_MOVE_ARG(WriteHandler) handler);
 7 
 8     void close();
 9     boost::system::error_code close(boost::system::error_code& ec);
10 };

AsyncWriteStream在Stream的基础上增加了一个异步写数据的接口async_write_some,第一个参数buffers是一个符合ConstBufferSequence约束的对象,第二个参数是异步操作的回调函数。

SyncReadStream的约束摘要如下:

 1 class SyncReadStream
 2 {
 3 public:
 4     template <typename MutableBufferSequence>
 5     void read_some(const MutableBufferSequence& buffers);
 6 
 7     template <typename MutableBufferSequence>
 8     boost::system::error_code read_some(const MutableBufferSequence& buffers, boost::system::error_code& ec);
 9 
10     void close();
11     boost::system::error_code close(boost::system::error_code& ec);
12 };

SyncReadStream在Stream的基础上增加了一个异步读数据的接口read_some,第一个参数buffers是一个符合MutableBufferSequence约束的对象。

SyncWriteStream的约束摘要如下:

1 class SyncWriteStream
 2 {
 3 public:
 4     template <typename ConstBufferSequence>
 5     void write_some(const ConstBufferSequence& buffers);
 6 
 7     template <typename ConstBufferSequence>
 8     boost::system::error_code write_some(const ConstBufferSequence& buffers, boost::system::error_code& ec);
 9 
10     void close();
11     boost::system::error_code close(boost::system::error_code& ec);
12 };

SyncWriteStream在Stream的基础上增加了一个同步写数据的接口write_some,第一个参数buffers是一个符合ConstBufferSequence约束的对象。

5、泛型与面向对象的完美结合

本章中你将看到asio中对泛型编程和面向对象编程两种范式的结合使用,为你打开多范式混合编程的大门。在这里,泛型编程和面向对象编程两种编程范式相辅相成、取长补短,发挥出了单一编程范式无法比拟的强大威力,堪称多范式编程语言的应用典范。

5.1Service Concept

Service,与basic_io_object结合时是一种泛型Concept,与io_service和service_registry结合时是面向对象思想中service_base的泛化类型。

Service作为泛型Concept时,其约束摘要如下:

1 class Service
2 {
3 public:
4     typedef ... implementation_type;
5 
6     void construct(implementation_type& );
7     void destroy(implementation_type& );
8     io_service& get_io_service();
9 };

其中,implementation_type是Service对应的I/O对象持有的句柄类型,basic_io_object在构造/析构时会调用construct/destroy接口注册/注销到Service中。

Service与io_service和service_registry结合时,要求其必须继承于service_base。 service_base及其基类io_service::service的类摘要如下:

 1 class io_service::service
 2   : private noncopyable
 3 {
 4 public:
 5   boost::asio::io_service& get_io_service();
 6 
 7 protected:
 8   service(boost::asio::io_service& owner);
 9   virtual ~service();
10 
11 private:
12   virtual void shutdown_service() = 0;
13 
14   virtual void fork_service(boost::asio::io_service::fork_event event);
15 
16   friend class boost::asio::detail::service_registry;
17   struct key
18   {
19     key() : type_info_(0), id_(0) {}
20     const std::type_info* type_info_;
21     const boost::asio::io_service::id* id_;
22   } key_;
23 
24   boost::asio::io_service& owner_;
25   service * next_;
26 };
27 
28 template <typename Type>
29 class service_base : public io_service::service
30 {
31 public:
32   static boost::asio::detail::service_id<Type> id;
33 
34   service_base(boost::asio::io_service& io_service) : io_service::service(io_service) {}
35 };

其中,Service在service_registry中是以侵入式的单链表存储的,io_service::service中成员next_即是指向下一个Service的指针。service_base类的模板参数Type即是Service的类型,Service在继承service_base时的写法大致如下:

1 class Service
2     : public service_base<Service>
3 {
4 };

将两种约束结合,得到一个最简单的可以与I/O对象搭配使用的Service的写法如下:

 1 class Service
 2     : public service_base<Service>
 3 {
 4 public:
 5     typedef ... implementation_type;
 6 
 7     void construct(implementation_type&);
 8     void destroy(implementation_type&);
 9     io_service& get_io_service();
10 };

5.2CSU(Core-Service-User架构)

第一章中单纯从面向对象的角度介绍过Asio的核心架构,本节不再局限于单一编程范式,从源码分析开始剖析Asio的核心架构。

Asio的核心架构是由三大组件构成,其分别是:

  • 让用户直接使用,为用户提供接口的组件,暂且称之为User;

  • 无需用户感知的,为User的接口提供实现的服务组件,称为Service;

  • 负责组合多个Service,并辅助User对象的实例化的核心组件,称为Core;

这种由Core-Service-User三部分组成的架构,为行文方便暂且简称为CSU。

在Asio的CSU架构中,io_service以及几个关联类和内部类扮演了Core的角色;之前提到的ServiceConcept约定了Service的扩展方式;本节以一个Service及其对应的I/O对象为例介绍CSU的实现。为了易于理解,将源码中用于实现CSU的部分摘要出来,忽略与CSU无关的代码,并做一些小幅度修改。

Core相关代码摘要:

 1 class io_service
 2 {
 3     // 持有一个service_registry对象
 4     service_registry * service_registry_;
 5 };
 6 
 7 // 返回ios中服务类型是Service的服务的引用
 8 template <typename Service> Service& use_service(io_service& ios);
 9 
10 // 给ios添加服务svc
11 template <typename Service> void add_service(io_service& ios, Service* svc);
12 
13 // 判断ios中是否有服务类型是Service的服务
14 template <typename Service> bool has_service(io_service& ios);
15 
16 // 所有Service的根基类
17 class io_service::service
18 {
19 };
20 
21 // 用于组合多个Service
22 class service_registry
23 {
24     io_service::service * service_list_;
25 
26 private:
27     /// 以下三个函数是同名自由函数的真正实现
28     template <typename Service> Service& use_service();
29     template <typename Service> void add_service(Service* svc);
30     template <typename Service> bool has_service();
31 };
32 
33 // 所有Service的直接父类,Type必须为Service自身类型。
34 template <typename Type>
35 class service_base
36 {
37     static service_id<Type> id;
38 };

Service,以deadline_timer_service为例:

 1 // 定时器服务
  2 template <typename TimeType,
  3     typename TimeTraits = boost::asio::time_traits<TimeType> >
  4 class deadline_timer_service
  5 {
  6 private:
  7   typedef detail::deadline_timer_service<traits_type> service_impl_type;
  8 
  9 public:
 10   typedef typename service_impl_type::implementation_type implementation_type;
 11 
 12   /// Construct a new timer service for the specified io_service.
 13   explicit deadline_timer_service(boost::asio::io_service& io_service)
 14     : boost::asio::detail::service_base<
 15         deadline_timer_service<TimeType, TimeTraits> >(io_service),
 16       service_impl_(io_service)
 17   {
 18   }
 19 
 20   /// Construct a new timer implementation.
 21   void construct(implementation_type& impl)
 22   {
 23     service_impl_.construct(impl);
 24   }
 25 
 26   /// Destroy a timer implementation.
 27   void destroy(implementation_type& impl)
 28   {
 29     service_impl_.destroy(impl);
 30   }
 31 
 32   /// Cancel any asynchronous wait operations associated with the timer.
 33   std::size_t cancel(implementation_type& impl, boost::system::error_code& ec)
 34   {
 35     return service_impl_.cancel(impl, ec);
 36   }
 37 
 38   /// Cancels one asynchronous wait operation associated with the timer.
 39   std::size_t cancel_one(implementation_type& impl,
 40       boost::system::error_code& ec)
 41   {
 42     return service_impl_.cancel_one(impl, ec);
 43   }
 44 
 45   /// Get the expiry time for the timer as an absolute time.
 46   time_type expires_at(const implementation_type& impl) const
 47   {
 48     return service_impl_.expires_at(impl);
 49   }
 50 
 51   /// Set the expiry time for the timer as an absolute time.
 52   std::size_t expires_at(implementation_type& impl,
 53       const time_type& expiry_time, boost::system::error_code& ec)
 54   {
 55     return service_impl_.expires_at(impl, expiry_time, ec);
 56   }
 57 
 58   /// Get the expiry time for the timer relative to now.
 59   duration_type expires_from_now(const implementation_type& impl) const
 60   {
 61     return service_impl_.expires_from_now(impl);
 62   }
 63 
 64   /// Set the expiry time for the timer relative to now.
 65   std::size_t expires_from_now(implementation_type& impl,
 66       const duration_type& expiry_time, boost::system::error_code& ec)
 67   {
 68     return service_impl_.expires_from_now(impl, expiry_time, ec);
 69   }
 70 
 71   // Perform a blocking wait on the timer.
 72   void wait(implementation_type& impl, boost::system::error_code& ec)
 73   {
 74     service_impl_.wait(impl, ec);
 75   }
 76 
 77   // Start an asynchronous wait on the timer.
 78   template <typename WaitHandler>
 79   BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler,
 80       void (boost::system::error_code))
 81   async_wait(implementation_type& impl,
 82       BOOST_ASIO_MOVE_ARG(WaitHandler) handler)
 83   {
 84     detail::async_result_init<
 85       WaitHandler, void (boost::system::error_code)> init(
 86         BOOST_ASIO_MOVE_CAST(WaitHandler)(handler));
 87 
 88     service_impl_.async_wait(impl, init.handler);
 89 
 90     return init.result.get();
 91   }
 92 
 93 private:
 94   // Destroy all user-defined handler objects owned by the service.
 95   void shutdown_service()
 96   {
 97     service_impl_.shutdown_service();
 98   }
 99 
100   // The platform-specific implementation.
101   service_impl_type service_impl_;
102 };

User相关代码,以basic_deadline_timer为例:

 1 template <typename IoObjectService>
 2 class basic_io_object
 3 {
 4 public:
 5   typedef IoObjectService service_type;
 6   typedef typename service_type::implementation_type implementation_type;
 7 
 8   boost::asio::io_service& get_io_service();
 9 
10 protected:
11   explicit basic_io_object(boost::asio::io_service& io_service)
12     : service_(&boost::asio::use_service<IoObjectService>(io_service))
13   {
14     service_->construct(implementation);
15   }
16 
17   ~basic_io_object()
18   {
19     service_->destroy(implementation);
20   }
21 
22   service_type& get_service()
23   {
24     return *service_;
25   }
26 
27   const service_type& get_service() const
28   {
29     return *service_;
30   }
31 
32   implementation_type& get_implementation()
33   {
34     return implementation;
35   }
36 
37   const implementation_type& get_implementation() const
38   {
39     return implementation;
40   }
41 
42   implementation_type implementation;
43 
44 private:
45   basic_io_object(const basic_io_object&);
46   void operator=(const basic_io_object&);
47 
48   IoObjectService* service_;
49 };
50 
51 template <typename Time,
52     typename TimeTraits = boost::asio::time_traits<Time>,
53     typename TimerService = deadline_timer_service<Time, TimeTraits> >
54 class basic_deadline_timer
55   : public basic_io_object<TimerService>
56 {
57 public:
58   /// 三个构造函数均需要io_service&
59   explicit basic_deadline_timer(boost::asio::io_service& io_service);
60   basic_deadline_timer(boost::asio::io_service& io_service, const time_type& expiry_time);
61   basic_deadline_timer(boost::asio::io_service& io_service, const duration_type& expiry_time);
62 
63   
64   /// @{ 功能性接口
65   std::size_t cancel();
66   std::size_t cancel(boost::system::error_code& ec);
67   std::size_t cancel_one();
68   std::size_t cancel_one(boost::system::error_code& ec);
69 
70   time_type expires_at() const;
71   std::size_t expires_at(const time_type& expiry_time);
72   std::size_t expires_at(const time_type& expiry_time, boost::system::error_code& ec);
73 
74   duration_type expires_from_now() const;
75   std::size_t expires_from_now(const duration_type& expiry_time);
76   std::size_t expires_from_now(const duration_type& expiry_time, boost::system::error_code& ec);
77 
78   void wait();
79   void wait(boost::system::error_code& ec);
80 
81   template <typename WaitHandler>
82     BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, void (boost::system::error_code))
83   async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler);
84   /// @}
85   /
86 };

在basic_deadline_timer和其对应服务deadline_timer_service的源码中可以很清晰的看到,他们都有名为cancel/cancel_one/expires_at/expires_from_now/wait/async_wait的函数,这些是deadline_timer对外提供的功能接口;basic_deadline_timer类中的这些接口只是对deadline_timer_service中同名接口的封装。

在Asio的CSU架构中,用泛型编程的方式约束Service和User,使他们拥有极强的扩展性;用面向对象的手段联结Core-Service-User三大组件,从用户的角度看,产生类似于“高内聚”的效果,让用户可以以简单而统一的接口使用asio,不必自行处理高难度的泛型组件的组装工作。

六. 扩展Asio(后续更新)

七. 基于Asio封装更易用的网络库bexio(后续更新)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/790916.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HCIA练习4

题目如下&#xff1a; 目录 第一步&#xff1a;IP的规划 第二步&#xff1a;缺省路由 第三步&#xff1a;开启telnet 第四步&#xff1a;编写ACL表 第五步&#xff1a;测试 思路分析&#xff1a; 华为默认允许所有&#xff0c;所以我们可以先写拒绝要求&#xff0c;再写允…

MobaXterm通过SSH访问Ubuntu服务器遇到的一个问题

在Windows下的MobaXterm界面配置完ubuntuIP以后显示access denied&#xff0c;排查发现是因为在ubuntu那边忘记安装了SSH Serve&#xff0c;安装过程如下&#xff1a; 第一步&#xff1a;安装所需包 让我们从打开终端输入一些必要命令开始。 注意&#xff0c;在安装新的包或…

【独家解答】面试题曝光:Spring容器中的Bean会不会被GC?

大家好&#xff0c;我是你们的小米&#xff01;今天&#xff0c;我们来聊一个有关Spring容器中的Bean的话题&#xff0c;也是面试中经常被问到的问题&#xff1a;“Spring 容器中的Bean是否会被GC呢&#xff1f;为什么&#xff1f;”让我们一起揭开这个神秘的面纱&#xff0c;解…

记录一次软件安全测试过程

一.前言 xx的安测已经过去一段时间了,这两天xx需求刚发布。xx的外呼需求文档还没确定,所以趁着这个时间,进行一下复盘。这次xx安测,全程参与,经历了3轮,从5月份开始,到6月底正式通过安测,实属不易。安测主要分为漏洞扫描、越权扫描、日志审查、软件版本基线检查下面也将…

Visual Studio 2022 程序员必须知道高效调试手段与技巧(上)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言&#x1f4ac; 什么是bug&#xff1f;&#x1f4ac; 调试是什么&#xff1f;有多重要&#x…

css设置八等分圆

现需要上图样式的布局&#xff0c;我通过两张向右方的图片&#xff0c;通过定位和旋转完成了布局。 问题&#xff1a; 由于是通过旋转获取到的样式&#xff0c;实际的盒子是一个长方形&#xff0c;当鼠标移入对应的箭头时选中的可能是其他盒子&#xff0c;如第一张设计稿可以看…

uniapp 语音文本播报功能

最近uniapp项目上遇到一个需求 就是在接口调用成功的时候加上语音播报 &#xff0c; ‘创建成功’ ‘开始成功’ ‘结束成功’ 之类的。 因为是固定的文本 &#xff0c;所以我先利用工具生成了 文本语音mp3文件&#xff0c;放入项目中&#xff0c;直接用就好了。 这里用到的工…

Android adb shell 查看App内存(java堆内存/vss虚拟内存/详细的内存状况/内存快照hprof)和系统可用内存

1.adb shell 获取app 进程的pid adb shell "ps|grep com.xxx包名"根据某个渠道包&#xff0c;去查询对应的pid&#xff0c;如下所示&#xff1a; 2.通过adb shell 查看设备的java dalvik 堆内存的最大值 执行命令行&#xff1a; adb shell getprop dalvik.vm.h…

【Java SE】继承与多态

目录 【1】继承 【1.1】为什么要继承 【1.2】继承概念 【1.3】继承的语法 【1.4】父类成员访问 【1.4.1】子类中访问父类的成员变量 【1.4.2】子类中访问父类的成员变量 【1.5】super关键字 【1.6】子类构造方法 【1.7】super和this 【1.8】再谈初始化 【1.9】prot…

element-plus中的collapse组件中的箭头图标移到左边问题解决(改进版)

1、问题BUG 这个问题虽然解决了&#xff0c;但是依旧有一些bug&#xff0c;首先我们来看一下&#xff0c;他的样式变成了什么样的。 下面就是我们修改后的样子了&#xff0c;但是对于我们的需求来说&#xff0c;左边的箭头样式是没问题了 可是到了箭头到了右边却变成了下面的…

17_LinuxLCD驱动

目录 Framebuffer设备 LCD驱动简析 LCD驱动程序编写 LCD屏幕参数节点信息修改 LCD 屏幕背光节点信息 使能Linux logo显示 设置LCD作为终端控制台 Framebuffer设备 先来回顾一下裸机的时候LCD驱动是怎么编写的,裸机LCD驱动编写流程如下: 1.初始化I.MX6U的eLCDIF控制器,…

Gumbel Softmax Trick

Gumbel Softmax Trick 重参数化技巧&#xff08;re-parameters trick&#xff09;Gumbel softmax trick基于Softmax的采样基于Gumbel-max的采样基于Gumbel-softmax采样Softmax中的温度系数tau 算法学习之gumbel softmax 【Learning Notes】Gumbel 分布及应用浅析 gumbel-softma…

Failed to connect to 127.0.0.1 port 7890科学上网导致的问题

找了很多种解法&#xff1a; 首先这个.config配置文件有两个地方存在&#xff1a;先使用第一种方式&#xff0c;不管用再试第二种 第一个位置git安装路径&#xff1a;不需要重启 E:\git\Git\etc&#xff0c;这个需要看你自己的安装路径&#xff0c;找到http_proxy删除即可第二…

类型转换函数

再论类型转换 标准数据类型之间会进行隐式的类型安全转换 转换规则如下&#xff1a; 问题 普通类型与类类型之间能否进行类型转换&#xff1f; 类类型之间能否进行类型转换&#xff1f; 再论构造函数 构造函数可以定义不同类型的参数 参数满足下列条件时称为转换构造函数…

LocalDateTime的json格式化问题

目录 解决&#xff1a; 1、注册日期序列化器 2、自定义LocalDateTime的JSON格式 3、使用第三方库 总结&#xff1a; 实体类中定义了LocalDateTime类型的属性&#xff0c;获取数据会出现以下日期格式问题&#xff1a; 讲述&#xff1a; 对于LocalDateTime的JSON序列化和反序…

解析数据可视化工具:如何选择最合适的软件

在当今信息爆炸的时代&#xff0c;数据已成为各行各业的重要资源。为了更好地理解和分析数据&#xff0c;数据可视化成为一种必不可少的工具。市面上数据可视化工具不说上千也有上百&#xff0c;什么帆软、powerbi、把阿里datav&#xff0c;腾讯云图、山海鲸可视化等等等等&…

【VCS】(6)Code Coverage

Code Coverage VCS 中 Code Coverage 的类型Code Coverage Flow代码覆盖率选项Lab Code Coverage初步尝试其他格式的覆盖率报告屏蔽部分代码屏蔽整个模块 设计和验证到底要做到什么程度&#xff1f; 这里其中一个指标就是 Code Coverage。 代码覆盖率一般考虑以下几个方面&…

前置操作符和后置操作符

下面的代码有没有区别&#xff1f;为什么&#xff1f; 意想不到的事实 现代编译器产品会对代码进行优化 优化使得最终的二进制程序更加高效 优化后的二进制程序丢失了 C/C 的原生语义 不可能从编译后的二进制程序还原 C/C 程序 思考 操作符可以重载吗&#xff1f; 如何区分…

V1.4基站仓储三代标签操作指导

一、管理系统使用 1、启动v1.4基站 插上电源&#xff0c;用网线连接基站和电脑。基站默认ip为192.168.1.200&#xff0c;所以需要修改电脑的IP地址为192.168.1.x&#xff0c;例如&#xff1a;192.168.1.100 ​ 注&#xff1a;当基站第二个灯&#xff08;绿色&#xff09;闪烁…

DAY12_JSPEL表达式JSTL标签MVC模式和三层架构

目录 1 JSP 概述2 JSP 快速入门2.1 搭建环境2.2 导入 JSP 依赖2.3 创建 jsp 页面2.4 编写代码2.5 测试 3 JSP 原理4 JSP 脚本4.1 JSP 脚本分类4.2 案例4.2.1 需求4.2.2 实现4.2.3 成品代码4.2.4 测试 4.3 JSP 缺点 5 EL 表达式5.1 概述5.2 代码演示5.3 域对象 6 JSTL标签6.1 概…