0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Boost.asio源碼剖析

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-09 14:36 ? 次閱讀

1、前言

Boost庫是一個可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進程的開發(fā)引擎之一。Boost庫由C++標(biāo)準(zhǔn)委員會庫工作組成員發(fā)起,其中有些內(nèi)容有望成為下一代C++標(biāo)準(zhǔn)庫內(nèi)容。在C++社區(qū)中影響甚大,是不折不扣的“準(zhǔn)”標(biāo)準(zhǔn)庫。

boost.asio是Boost庫中非常著名的I/O組件,是用于網(wǎng)絡(luò)和低層IO編程的跨平臺C++庫,為開發(fā)者提供了C++環(huán)境下穩(wěn)定的異步模型。其在性能、移植性、擴展性等方面均為人稱道,甚至被很多業(yè)內(nèi)人士稱為“網(wǎng)絡(luò)神器”。asio是目前唯一有希望進入C++標(biāo)準(zhǔn)庫以彌補標(biāo)準(zhǔn)庫在網(wǎng)絡(luò)方面的缺失的C++網(wǎng)絡(luò)庫,因此對asio的學(xué)習(xí)在某種意義上可以說是學(xué)習(xí)C++網(wǎng)絡(luò)編程的必修課。

當(dāng)前網(wǎng)絡(luò)上從用戶角度介紹asio的文獻很多也很完善,所以本文決定另辟蹊徑,從asio源碼角度出發(fā),由內(nèi)而外、深入淺出地剖析asio的架構(gòu)和設(shè)計理念,將asio的一切秘密呈現(xiàn)在讀者眼前。

本文適合已有較完善的C++基礎(chǔ)知識、具備一定程度的泛型技術(shù)和面向?qū)ο蠹夹g(shù)、并對boost.asio有一定的了解的讀者。

2、架構(gòu)淺析

先來看一下asio的0層的組件圖。

圖片

(圖1.0)

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

services服務(wù)是邏輯功能的實現(xiàn)者,其中包含提供定時功能的deadline_timer_service、提供socket相關(guān)功能的win_iocp_socket_service(windows平臺)/reactive_socket_service(其他平臺)、作為io_service功能的真正實現(xiàn)者win_iocp_io_service(windows平臺)/task_io_service(其他平臺)等等服務(wù)。

"Asio核心組件"在這一層中可以理解為就是io_service,它通過關(guān)聯(lián)的類service_registry將實現(xiàn)具體功能所需的服務(wù)組合起來,再由io_object提供接口給用戶使用。

這三大組件構(gòu)成了asio的核心架構(gòu),asio的一切都是以此為根基衍生擴展出來的。

讓我們將圖1.0進一步細化:

圖片

(圖1.1)

“Asio核心組件”細化為4個類:io_service,service_registry,service,service_base。其中,service_registry負責(zé)管理所有服務(wù),使用延遲創(chuàng)建技術(shù),在真正使用服務(wù)對象的時候才創(chuàng)建服務(wù)對象,并以單鏈表的方式管理,但只能增不能刪,直到service_registry析構(gòu)時才會釋放其管理的服務(wù)對象。service是io_service的類中類,是一個虛基類,所有由service_registry管理的服務(wù)都必須從service派生。service_base是service的直接派生類,是services繼承體系的第二級,組合了service_id,目前asio中所有服務(wù)均繼承與service_base。

“I/O對象”細化為basic_io_object及其派生類。basic_io_object是所有I/O對象的基類,提供I/O對象與其對應(yīng)服務(wù)的聯(lián)系。 再將圖1.1進一步細化(關(guān)注網(wǎng)絡(luò)I/O方面的一些類,其他方面的類未畫出):

圖片

(圖1.2)

io_service的真正邏輯實現(xiàn)封裝在內(nèi)部橋接的類io_service_impl中,io_service_impl是一個typedef(在windows平臺下是win_iocp_io_service,其他平臺下是task_io_service)。io_service_impl就是一個繼承于service_base的服務(wù),在io_service初始化也就是其關(guān)聯(lián)類service_registry初始化時被創(chuàng)建,再由io_service持有其引用。

從圖中可以看到,繼承于service_base的服務(wù)有:

strand_service:提供串行化多線程調(diào)用的功能

       deadline_timer_service:提供定時器功能

       stream_socket_service:提供流式socket相關(guān)功能

       datagram_socket_service:提供報文式socket相關(guān)功能

       seq_packet_socket_service:提供seq_packet socket相關(guān)功能

       raw_socket_service:提供原始套接字相關(guān)功能

       socket_acceptor_service:提供端口監(jiān)聽和接受客戶端連接相關(guān)功能

這些服務(wù)都是幕后英雄,對于用戶而言是感知不到的,用戶使用的都是其對應(yīng)的I/O對象。

這些服務(wù)對應(yīng)的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 // 異步連接回調(diào)函數(shù)
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; // 創(chuàng)建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); // 創(chuàng)建tcp協(xié)議的socket對象
19 conn_socket.async_connect(addr, &on_connect); // 發(fā)起異步連接請求
20 ios.run(); // 調(diào)用io_service::run, 等待異步操作結(jié)果
21
22 std::cin.get();
23 return 0;
24 }

這段代碼中的異步連接請求在asio源碼中的序列圖如下:

圖片

其中,basic_socket是個模板類,tcp協(xié)議中的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模型處理的,這是與異步讀寫數(shù)據(jù)最大的不同之處。

3.2常見流程分析之二(Tcp異步接受連接)

我們用一個簡單的demo分析Tcp異步連接的流程:

1 #include
2 #include
3 #include
4
5 // 異步連接回調(diào)函數(shù)
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; // 創(chuàng)建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); // 創(chuàng)建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)); // 調(diào)用異步accept請求
26 ios.run(); // 調(diào)用io_service::run, 等待異步操作結(jié)果
27
28 std::cin.get();
29 return 0;
30 }

這段代碼中的異步連接請求在asio源碼中的序列圖如下:

圖片

3.3常見流程分析之三(Tcp異步讀寫數(shù)據(jù))

我們依然以上一節(jié)的例子為基礎(chǔ),擴展一個簡單的demo分析Tcp異步讀寫數(shù)據(jù)的流程:


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 // 異步讀數(shù)據(jù)回調(diào)函數(shù)
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 // 異步寫數(shù)據(jù)回調(diào)函數(shù)
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 // 異步連接回調(diào)函數(shù)
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; // 創(chuàng)建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); // 創(chuàng)建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)); // 調(diào)用異步accept請求
68 ios.run(); // 調(diào)用io_service::run, 等待異步操作結(jié)果
69
70 std::cout << "press enter key...";
71 std::cin.get();
72 return 0;
73 } ,>

這段代碼中的異步連接請求在asio源碼中的序列圖如下:

圖片

3.4常見流程分析之四(Tcp強制關(guān)閉連接)

我們依然以上一節(jié)的例子為基礎(chǔ),擴展一個簡單的demo分析Tcp強制關(guān)閉連接的流程:

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 // 異步讀數(shù)據(jù)回調(diào)函數(shù)
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 // 異步寫數(shù)據(jù)回調(diào)函數(shù)
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 // 異步連接回調(diào)函數(shù)
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 /// 強制關(guān)閉連接
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; // 創(chuàng)建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); // 創(chuàng)建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)); // 調(diào)用異步accept請求
73 socket_ptr.reset();
74 ios.run(); // 調(diào)用io_service::run, 等待異步操作結(jié)果
75
76 std::cout << "press enter key...";
77 std::cin.get();
78 return 0;
79 } ,>

這個例子中,接受到客戶端的連接后,立即發(fā)起異步讀請求和異步寫請求,然后立即強制關(guān)閉socket。

其中,強制關(guān)閉socket的請求在asio源碼中的序列圖如下:

圖片

3.5常見流程分析之五(Tcp優(yōu)雅地關(guān)閉連接)

我們依然以第三節(jié)的例子為基礎(chǔ),擴展一個簡單的demo分析Tcp優(yōu)雅地關(guān)閉連接的流程:

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 // 異步讀數(shù)據(jù)回調(diào)函數(shù)
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 // 異步寫數(shù)據(jù)回調(diào)函數(shù)
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 /// 優(yōu)雅地關(guān)閉連接
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 // 異步連接回調(diào)函數(shù)
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; // 創(chuàng)建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); // 創(chuàng)建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)); // 調(diào)用異步accept請求
89 socket_ptr.reset();
90 ios.run(); // 調(diào)用io_service::run, 等待異步操作結(jié)果
91
92 std::cout << "press enter key...";
93 std::cin.get();
94 return 0;
95 },>

這個例子中,接收到客戶端的連接并向客戶端發(fā)送數(shù)據(jù)以后,先關(guān)閉socket的發(fā)送通道,然后等待socket接收緩沖區(qū)中的數(shù)據(jù)全部read出來以后,再關(guān)閉socket的接收通道。此時,socket的接收和發(fā)送通道均以關(guān)閉,任何進程都無法使用此socket收發(fā)數(shù)據(jù),但其所占用的系統(tǒng)資源并未釋放,底層發(fā)送緩沖區(qū)中的數(shù)據(jù)也不保證已全部發(fā)出,需要在此之后執(zhí)行close操作以便釋放系統(tǒng)資源。

若在釋放系統(tǒng)資源前希望底層發(fā)送緩沖區(qū)中的數(shù)據(jù)依然可以發(fā)出,則需在socket的linger屬性中設(shè)置一個等待時間,以便有時間等待發(fā)送緩沖區(qū)中的數(shù)據(jù)發(fā)送完畢。但linger中的值絕對不是越大越好,這是因為其原理是操作系統(tǒng)幫忙保留socket的資源以等待其發(fā)送緩沖區(qū)中的數(shù)據(jù)發(fā)送完畢,如果遠端socket的一直未能接收數(shù)據(jù)便會導(dǎo)致本地socket一直等待下去,這對系統(tǒng)資源是極大的浪費。因此,在需要處理大量連接的服務(wù)端,linger的值一定不可過大。

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

4.1Protocol(通信協(xié)議)

Protocol,是asio在網(wǎng)絡(luò)編程方面最重要的一個concept。在第一章中的levelX類圖中可以看到,所有提供網(wǎng)絡(luò)相關(guān)功能的服務(wù)和I/O對象都需要Protocol來確定一些細節(jié)。

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三個接口,分別返回協(xié)議類型/協(xié)議枚舉/協(xié)議組枚舉;還需要提供兩個類型定義endpoint/socket,分別表示通信協(xié)議一方的地址/繼承于asio::basic_socket的類型。

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

既符合Protocol約束,同時又符合InternetProtocol約束的類有:tcp(TCP協(xié)議),udp(UDP協(xié)議),icmp(ICMP協(xié)議)。

4.2InternetProtocol(網(wǎng)絡(luò)通信協(xié)議)

InternetProtocol,是Protocol的約束超集,在Protocol約束的基礎(chǔ)上添加了幾個新的約束。

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兩個靜態(tài)接口,分別返回IPv4/IPv6版本的網(wǎng)絡(luò)通信協(xié)議對象;類型定義resolver,表示繼承于basic_resolver的類型。

4.3ConstBuffer(不可變緩沖區(qū)),ConstBufferSequence(不可變緩沖區(qū)序列),MutableBuffer(可變緩沖區(qū)),MutableBufferSequence(可變緩沖區(qū)序列)

ConstBuffer和MutableBuffer是asio中各種組件通用的緩沖區(qū)適配器concept,在asio中以const_buffer和mutable_buffer兩個類實現(xiàn)。

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這兩個自由函數(shù)獲取緩沖區(qū)首地址指針和緩沖區(qū)長度即可。這兩個concept沒有什么擴展的必要,因此asio中并未顯式地提及,在后文中我們直接以他們當(dāng)前的實現(xiàn)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兩個接口,返回相應(yīng)的迭代器即可。

asio中,提供了const_buffer_1和mutable_buffer_1兩個類,可以方便地將單個的const_buffer和mutable_buffer封裝為容器外觀,使其符合ConstBufferSequence和MutableBufferSequence約束。

4.4Stream(流),AsyncReadStream(支持異步讀操作的流),AsyncWriteStream(支持異步寫操作的流),SyncReadStream(支持同步寫操作的流),SyncWriteStream(支持同步寫操作的流)

Stream,就是大家耳熟能詳?shù)摹傲鳌薄?/p>

AsyncReadStream,AsyncWriteStream,SyncReadStream,SyncWriteStream四種concept是Stream的子集,在流的基礎(chǔ)上添加一些接口。

Stream的約束摘要如下:

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

Stream的約束非常簡單,只需要兩個用于關(guān)閉流的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的基礎(chǔ)上增加了一個異步讀數(shù)據(jù)的接口async_read_some,第一個參數(shù)buffers是一個符合MutableBufferSequence約束的對象,第二個參數(shù)是異步操作的回調(diào)函數(shù)。

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的基礎(chǔ)上增加了一個異步寫數(shù)據(jù)的接口async_write_some,第一個參數(shù)buffers是一個符合ConstBufferSequence約束的對象,第二個參數(shù)是異步操作的回調(diào)函數(shù)。

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的基礎(chǔ)上增加了一個異步讀數(shù)據(jù)的接口read_some,第一個參數(shù)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的基礎(chǔ)上增加了一個同步寫數(shù)據(jù)的接口write_some,第一個參數(shù)buffers是一個符合ConstBufferSequence約束的對象。

5、泛型與面向?qū)ο蟮耐昝澜Y(jié)合

本章中你將看到asio中對泛型編程和面向?qū)ο缶幊虄煞N范式的結(jié)合使用,為你打開多范式混合編程的大門。在這里,泛型編程和面向?qū)ο缶幊虄煞N編程范式相輔相成、取長補短,發(fā)揮出了單一編程范式無法比擬的強大威力,堪稱多范式編程語言的應(yīng)用典范。

5.1Service Concept

Service,與basic_io_object結(jié)合時是一種泛型Concept,與io_service和service_registry結(jié)合時是面向?qū)ο笏枷胫衧ervice_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對應(yīng)的I/O對象持有的句柄類型,basic_io_object在構(gòu)造/析構(gòu)時會調(diào)用construct/destroy接口注冊/注銷到Service中。

Service與io_service和service_registry結(jié)合時,要求其必須繼承于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類的模板參數(shù)Type即是Service的類型,Service在繼承service_base時的寫法大致如下:

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

將兩種約束結(jié)合,得到一個最簡單的可以與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架構(gòu))

第一章中單純從面向?qū)ο蟮慕嵌冉榻B過Asio的核心架構(gòu),本節(jié)不再局限于單一編程范式,從源碼分析開始剖析Asio的核心架構(gòu)。

Asio的核心架構(gòu)是由三大組件構(gòu)成,其分別是:

  • 讓用戶直接使用,為用戶提供接口的組件,暫且稱之為User;
  • 無需用戶感知的,為User的接口提供實現(xiàn)的服務(wù)組件,稱為Service;
  • 負責(zé)組合多個Service,并輔助User對象的實例化的核心組件,稱為Core;

這種由Core-Service-User三部分組成的架構(gòu),為行文方便暫且簡稱為CSU。

在Asio的CSU架構(gòu)中,io_service以及幾個關(guān)聯(lián)類和內(nèi)部類扮演了Core的角色;之前提到的ServiceConcept約定了Service的擴展方式;本節(jié)以一個Service及其對應(yīng)的I/O對象為例介紹CSU的實現(xiàn)。為了易于理解,將源碼中用于實現(xiàn)CSU的部分摘要出來,忽略與CSU無關(guān)的代碼,并做一些小幅度修改。

Core相關(guān)代碼摘要:

1 class io_service
2 {
3 // 持有一個service_registry對象
4 service_registry * service_registry_;
5 };
6
7 // 返回ios中服務(wù)類型是Service的服務(wù)的引用
8 template Service& use_service(io_service& ios);
9
10 // 給ios添加服務(wù)svc
11 template void add_service(io_service& ios, Service* svc);
12
13 // 判斷ios中是否有服務(wù)類型是Service的服務(wù)
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 /// 以下三個函數(shù)是同名自由函數(shù)的真正實現(xiàn)
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 // 定時器服務(wù)
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相關(guān)代碼,以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 /// 三個構(gòu)造函數(shù)均需要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和其對應(yīng)服務(wù)deadline_timer_service的源碼中可以很清晰的看到,他們都有名為cancel/cancel_one/expires_at/expires_from_now/wait/async_wait的函數(shù),這些是deadline_timer對外提供的功能接口;basic_deadline_timer類中的這些接口只是對deadline_timer_service中同名接口的封裝。

在Asio的CSU架構(gòu)中,用泛型編程的方式約束Service和User,使他們擁有極強的擴展性;用面向?qū)ο蟮氖侄温?lián)結(jié)Core-Service-User三大組件,從用戶的角度看,產(chǎn)生類似于“高內(nèi)聚”的效果,讓用戶可以以簡單而統(tǒng)一的接口使用asio,不必自行處理高難度的泛型組件的組裝工作。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3521

    瀏覽量

    93269
  • Boost
    +關(guān)注

    關(guān)注

    5

    文章

    359

    瀏覽量

    47729
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    626

    瀏覽量

    28969
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2085

    瀏覽量

    73302
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4671

    瀏覽量

    67767
收藏 人收藏

    評論

    相關(guān)推薦

    Faster Transformer v2.1版本源碼解讀

    寫在前面 :本文將對 Faster Transformer v2.1 版本源碼進行解讀,重點介紹該版本基于 v1.0 和 v2.0 所做的優(yōu)化內(nèi)容,剖析源碼作者優(yōu)化意圖。 1 v2.1 版本發(fā)布背景
    的頭像 發(fā)表于 09-19 11:39 ?1169次閱讀
    Faster Transformer v2.1版本<b class='flag-5'>源碼</b>解讀

    #硬聲創(chuàng)作季 【Nacos源碼】Nacos心跳機制與服務(wù)健康檢查源碼剖析

    JAVA編程語言源碼
    Mr_haohao
    發(fā)布于 :2022年09月14日 07:05:57

    #硬聲創(chuàng)作季 【Nacos源碼】Nacos服務(wù)注冊與發(fā)現(xiàn)源碼深度剖析

    云計算源碼nacos
    Mr_haohao
    發(fā)布于 :2022年09月14日 07:10:33

    BOOST原理

    Boost
    YS YYDS
    發(fā)布于 :2023年07月02日 17:26:39

    STL源碼剖析中的,這個new是什么用法?這個函數(shù)的作用是?

    invoke copy constructor of T1}STL源碼剖析中的,這個new是什么用法?這個函數(shù)是用來干什么的
    發(fā)表于 03-21 10:47

    Redux設(shè)計思想與源碼解析

    Redux源碼剖析及應(yīng)用
    發(fā)表于 08-02 08:19

    音頻數(shù)據(jù)輸出ASIO和WASAPI

    數(shù)據(jù)至音效卡和解碼器,音頻輸出是何等重要。這裡需要注意的是,需要重視音頻數(shù)據(jù)輸出的僅僅是Windows系統(tǒng),而OS X早期設(shè)計時就是為專業(yè)音訊產(chǎn)業(yè)服務(wù),在OS X的系統(tǒng)底層中就有一個替代ASIO的解決
    發(fā)表于 09-18 09:05

    labview實現(xiàn)ASIO驅(qū)動

    背景:使用labview通過ASIO驅(qū)動方式控制外置聲卡,win10;1.我已經(jīng)有一個labview lib文件(waveio.lib)可以使用,但在win10上使用時,waveio_start總
    發(fā)表于 06-22 15:01

    做ROS與樹莓派進行通信

    最近在做ROS與樹莓派進行通信時,發(fā)現(xiàn)boost:asio庫還蠻強大的,就試著用asio寫了一個簡單的使用tcp傳輸軌跡數(shù)據(jù)到樹莓派,讓樹莓派控制步進電機旋轉(zhuǎn)的代碼。其實也就是將asio
    發(fā)表于 09-06 07:26

    使用新版gcc編譯含有使用asio網(wǎng)絡(luò)庫的項目出錯了怎么解決?

    使用到asio部分相同的代碼可以在gcc8.4的5.0版本中編譯通過,但在最新的gcc11.2中編譯失敗Code: Select all/home/dev/.espressif/tools
    發(fā)表于 03-07 08:56

    STL源碼剖析的PDF電子書免費下載

    學(xué)習(xí)編程的人都知道,閱讀、剖析名家代碼乃是提高水平的捷徑。源碼之前,了無秘密。大師們的縝密思維、經(jīng)驗結(jié)晶、技術(shù)思路、獨到風(fēng)格,都原原本本體現(xiàn)在源碼之中。
    發(fā)表于 06-29 08:00 ?0次下載
    STL<b class='flag-5'>源碼</b><b class='flag-5'>剖析</b>的PDF電子書免費下載

    基于asio的網(wǎng)絡(luò)通信框架asio2

    ./oschina_soft/gitee-asio2.zip
    發(fā)表于 06-22 11:33 ?2次下載
    基于<b class='flag-5'>asio</b>的網(wǎng)絡(luò)通信框架<b class='flag-5'>asio</b>2

    外置MOS大電流Boost

    根據(jù)Boost架構(gòu)類型不同,Boost可分為同步和異步兩個大類,實際應(yīng)用的時候,會結(jié)合工作電壓和應(yīng)用場景不同來選型,因此在此基礎(chǔ)上,微源Boost會有更細致的分類,主要分為四類:超低電壓輸入B
    的頭像 發(fā)表于 07-12 09:36 ?4120次閱讀

    Faster Transformer v1.0源碼詳解

    寫在前面:本文將對 Nvidia BERT 推理解決方案 Faster Transformer 源碼進行深度剖析,詳細分析作者的優(yōu)化意圖,并對源碼中的加速技巧進行介紹,希望對讀者有所幫助。本文
    的頭像 發(fā)表于 09-08 10:20 ?810次閱讀
    Faster Transformer v1.0<b class='flag-5'>源碼</b>詳解