1. 程式人生 > >boost::asio基本使用

boost::asio基本使用

char linux平臺 服務器 handler multiple img 可靠的 開始 syn

一、Asio網絡庫

  截止到C++17,C++標準庫都沒有加入網絡通信庫。實際項目網絡編程是非常常見的功能,直接使用操作系統API是低效率且不穩定的,比較好的方法是借助第三方成熟可靠的網絡庫。據我所知C++中目前比較有名的網絡庫有ACE、libevent和boost.Asio,這三個庫都是跨平臺的,各有特色,對於一般的應用來說,使用這些庫都是沒什麽問題。由於C++標準庫和boost庫的親緣關系,我經常使用boost中其它的庫,所以選擇了Asio庫。在網絡上搜索了大家對Asio的評價,發現Asio庫作為跨平臺的網絡庫還是相當優秀的。

  Linux系統高效網絡I/O是epoll,windows系統高效的網絡I/O是iocp,epoll是一種同步I/O復用技術,iocp是異步I/O。同步I/O指內核通知應用程序數據有了,應用程序可以獲取了;異步I/O是內核負責讀數據,讀好後通知應用程序可以用了。所以一般來說異步I/O相比同步I/O的效率更高一些,但是Linux中異步I/O(aio)並不比epoll高效。為了使的Asio庫跨平臺,最終Asio選擇Linux系統在epoll的基礎上用iocp的思想的封裝一層,這在一定上損失了Linux平臺I/O的效率。總的來說Asio網絡通信庫是主動器模式(proactor),而libevent使用的是reactor模式。

二、反應器模式/主動器模式

  反應器是比較容易理解的I/O模式,也是使用比較多的模式。主要內容來自於《IO設計模式:Reactor和Proactor對比》。

技術分享

Reactor包含如下角色:

  • Handle 句柄;用來標識socket連接或是打開文件;
  • Synchronous Event Demultiplexer:同步事件多路分解器:由操作系統內核實現的一個函數;用於阻塞等待發生在句柄集合上的一個或多個事件;(如select/epoll;)
  • Event Handler:事件處理接口
  • Concrete Event HandlerA:實現應用程序所提供的特定事件處理邏輯;
  • Reactor:反應器,定義一個接口,實現以下功能:

    1)供應用程序註冊和刪除關註的事件句柄;
    2)運行事件循環;
    3)有就緒事件到來時,分發事件到之前註冊的回調函數上處理;

技術分享

Proactor主動器模式包含如下角色

  • Handle 句柄;用來標識socket連接或是打開文件;
  • Asynchronous Operation Processor:異步操作處理器;負責執行異步操作,一般由操作系統內核實現;
  • Asynchronous Operation:異步操作
  • Completion Event Queue:完成事件隊列;異步操作完成的結果放到隊列中等待後續使用
  • Proactor:主動器;為應用程序進程提供事件循環;從完成事件隊列中取出異步操作的結果,分發調用相應的後續處理邏輯;
  • Completion Handler:完成事件接口;一般是由回調函數組成的接口;
  • Concrete Completion Handler:完成事件處理邏輯;實現接口定義特定的應用處理邏輯;

  主動和被動以主動寫為例,Reactor將handle放到select(),等待可寫就緒,然後調用write()寫入數據;寫完處理後續邏輯;Proactor調用aoi_write後立刻返回,由內核負責寫操作,寫完後調用相應的回調函數處理後續邏輯;可以看出,Reactor被動的等待指示事件的到來並做出反應;它有一個等待的過程,做什麽都要先放入到監聽事件集合中等待handler可用時再進行操作;Proactor直接調用異步讀寫操作,調用完後立刻返回。

三、基本使用

1.基本的同步客戶端架構

1 using boost::asio;
2 io_service service;
3 ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
4 ip::tcp::socket sock(service);
5 sock.connect(ep);

2.基本的同步服務器架構

 1 typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
 2 io_service service;
 3 ip::tcp::endpoint ep( ip::tcp::v4(), 2001)); // listen on 2001
 4 ip::tcp::acceptor acc(service, ep);
 5 while ( true) {
 6     socket_ptr sock(new ip::tcp::socket(service));
 7     acc.accept(*sock);
 8     boost::thread( boost::bind(client_session, sock));
 9 }
10 void client_session(socket_ptr sock) {
11     while ( true) {
12         char data[512];
13         size_t len = sock->read_some(buffer(data));
14         if ( len > 0)
15             write(*sock, buffer("ok", 2));
16     }

3.基本的異步客戶端架構

1 using boost::asio;
2 io_service service;
3 ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
4 ip::tcp::socket sock(service);
5 sock.async_connect(ep, connect_handler);
6 service.run();
7 void connect_handler(const boost::system::error_code & ec) {
8     // 如果ec返回成功我們就可以知道連接成功了
9 }

4.基本的異步服務器架構

 1 using boost::asio;
 2 typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
 3 io_service service;
 4 ip::tcp::endpoint ep( ip::tcp::v4(), 2001)); // 監聽端口2001
 5 ip::tcp::acceptor acc(service, ep);
 6 socket_ptr sock(new ip::tcp::socket(service));
 7 start_accept(sock);
 8 service.run();
 9 void start_accept(socket_ptr sock) {
10     acc.async_accept(*sock, boost::bind( handle_accept, sock, _1) );
11 }
12 void handle_accept(socket_ptr sock, const boost::system::error_code &
13 err) {
14     if ( err) return;
15     // 從這裏開始, 你可以從socket讀取或者寫入
16     socket_ptr sock(new ip::tcp::socket(service));
17     start_accept(sock);
18 }

參考:IO設計模式:Reactor和Proactor對比

《Boost.Asio C++網絡編程》

boost::asio基本使用