0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Boost.asio源码剖析

科技绿洲 来源:Linux开发架构之路 作者:Linux开发架构之路 2023-11-09 14:36 次阅读

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,目前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中还有串口通信信号处理等功能,在此不再一一赘述。

3、流程分析

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

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

1 #include
2 #include
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 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
2 #include
3 #include
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
2 #include
3 #include
4 #include
5 #include
6
7 typedef boost::shared_ptr socket_ptr_t;
8 typedef boost::array buffer_t;
9 typedef boost::shared_ptr 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
2 #include
3 #include
4 #include
5 #include
6
7 typedef boost::shared_ptr socket_ptr_t;
8 typedef boost::array buffer_t;
9 typedef boost::shared_ptr 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
2 #include
3 #include
4 #include
5 #include
6
7 typedef boost::shared_ptr socket_ptr_t;
8 typedef boost::array buffer_t;
9 typedef boost::shared_ptr 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
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
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
5 void read_some(const MutableBufferSequence& buffers);
6
7 template
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
5 void write_some(const ConstBufferSequence& buffers);
6
7 template
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
29 class service_base : public io_service::service
30 {
31 public:
32 static boost::asio::detail::service_id 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
3 {
4 };

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

1 class Service
2 : public service_base
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 Service& use_service(io_service& ios);
9
10 // 给ios添加服务svc
11 template void add_service(io_service& ios, Service* svc);
12
13 // 判断ios中是否有服务类型是Service的服务
14 template 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 Service& use_service();
29 template void add_service(Service* svc);
30 template bool has_service();
31 };
32
33 // 所有Service的直接父类,Type必须为Service自身类型。
34 template
35 class service_base
36 {
37 static service_id id;
38 };

Service,以deadline_timer_service为例:

1 // 定时器服务
2 template 3 typename TimeTraits = boost::asio::time_traits >
4 class deadline_timer_service
5 {
6 private:
7 typedef detail::deadline_timer_service 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 >(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
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
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(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 52 typename TimeTraits = boost::asio::time_traits,
53 typename TimerService = deadline_timer_service >
54 class basic_deadline_timer
55 : public basic_io_object
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
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,不必自行处理高难度的泛型组件的组装工作。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程
    +关注

    关注

    88

    文章

    3615

    浏览量

    93713
  • Boost
    +关注

    关注

    5

    文章

    370

    浏览量

    48099
  • 源码
    +关注

    关注

    8

    文章

    640

    浏览量

    29198
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73638
  • 代码
    +关注

    关注

    30

    文章

    4786

    浏览量

    68565
收藏 人收藏

    评论

    相关推荐

    Faster Transformer v2.1版本源码解读

    写在前面 :本文将对 Faster Transformer v2.1 版本源码进行解读,重点介绍该版本基于 v1.0 和 v2.0 所做的优化内容,剖析源码作者优化意图。 1 v2.1 版本发布背景
    的头像 发表于 09-19 11:39 1387次阅读
    Faster Transformer v2.1版本<b class='flag-5'>源码</b>解读

    #硬声创作季 【Nacos源码】Nacos心跳机制与服务健康检查源码剖析

    JAVA编程语言源码
    Mr_haohao
    发布于 :2022年09月14日 07:05:57

    #硬声创作季 【Nacos源码】Nacos集群CP架构底层Raft协议实现源码剖析

    云计算源码nacos
    Mr_haohao
    发布于 :2022年09月14日 07:09:26

    #硬声创作季 【Nacos源码】Nacos服务注册与发现源码深度剖析

    云计算源码nacos
    Mr_haohao
    发布于 :2022年09月14日 07:10:33

    BOOST原理

    Boost
    YS YYDS
    发布于 :2023年07月02日 17:26:39

    STL源码剖析中的,这个new是什么用法?这个函数的作用是?

    invoke copy constructor of T1}STL源码剖析中的,这个new是什么用法?这个函数是用来干什么的
    发表于 03-21 10:47

    Redux设计思想与源码解析

    Redux源码剖析及应用
    发表于 08-02 08:19

    音频数据输出ASIO和WASAPI

    數據至音效卡和解碼器,音頻輸出是何等重要。這裡需要注意的是,需要重視音頻數據輸出的僅僅是Windows系統,而OS X早期設計時就是為專業音訊產業服務,在OS X的系統底層中就有一個替代ASIO的解決
    发表于 09-18 09:05

    labview实现ASIO驱动

    背景:使用labview通过ASIO驱动方式控制外置声卡,win10;1.我已经有一个labview lib文件(waveio.lib)可以使用,但在win10上使用时,waveio_start总
    发表于 06-22 15:01

    做ROS与树莓派进行通信

    最近在做ROS与树莓派进行通信时,发现boost:asio库还蛮强大的,就试着用asio写了一个简单的使用tcp传输轨迹数据到树莓派,让树莓派控制步进电机旋转的代码。其实也就是将asio
    发表于 09-06 07:26

    使用新版gcc编译含有使用asio网络库的项目出错了怎么解决?

    使用到asio部分相同的代码可以在gcc8.4的5.0版本中编译通过,但在最新的gcc11.2中编译失败Code: Select all/home/dev/.espressif/tools
    发表于 03-07 08:56

    STL源码剖析的PDF电子书免费下载

    学习编程的人都知道,阅读、剖析名家代码乃是提高水平的捷径。源码之前,了无秘密。大师们的缜密思维、经验结晶、技术思路、独到风格,都原原本本体现在源码之中。
    发表于 06-29 08:00 0次下载
    STL<b class='flag-5'>源码</b><b class='flag-5'>剖析</b>的PDF电子书免费下载

    基于asio的网络通信框架asio2

    ./oschina_soft/gitee-asio2.zip
    发表于 06-22 11:33 2次下载
    基于<b class='flag-5'>asio</b>的网络通信框架<b class='flag-5'>asio</b>2

    外置MOS大电流Boost

    根据Boost架构类型不同,Boost可分为同步和异步两个大类,实际应用的时候,会结合工作电压和应用场景不同来选型,因此在此基础上,微源Boost会有更细致的分类,主要分为四类:超低电压输入B
    的头像 发表于 07-12 09:36 4436次阅读

    Faster Transformer v1.0源码详解

    写在前面:本文将对 Nvidia BERT 推理解决方案 Faster Transformer 源码进行深度剖析,详细分析作者的优化意图,并对源码中的加速技巧进行介绍,希望对读者有所帮助。本文
    的头像 发表于 09-08 10:20 971次阅读
    Faster Transformer v1.0<b class='flag-5'>源码</b>详解