C++並發 練習筆記(二)使用boost Asio的async I/O技術實作簡易網路聊天室 (下)

来源:互联网 发布:哈佛大学知乎 编辑:程序博客网 时间:2024/06/18 17:09

在上一 篇中C++並發 練習筆記(二)使用boost Asio的async I/O技術實作簡易網路聊天室 (上),

我們直接拿開發團隊的範例來做練習、並理解,但關於函數的使用方法及其意義並未太過深入介紹。

這次,我會比較詳細的紀錄並描述下來。



首先先來看一下再Asio當中一個同步的客戶端,是怎麼寫的。

using boost::asio;io_service service;ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);ip::tcp::socket sock(service);sock.connect(ep);                                   service.run();

其中,代碼中一定要創建一個 io_service的這個實體,boost::Asio利用它來跟系統的I/O設備通信,接著再創建

endpoint表示想要連結到的位置以及通訊協定,在此處ip::tcp::endpoint,使用IP協定以及TCP協定進行通信。

再來使用相同通信協定的socket庫來綁定ioservice,並用這個socket來連結到目標端點。

最後的run()函式用於告訴i/o設備開始收發數據。




接著來看一下剛剛同步客戶端跟現在異步客戶端之間的差別

using boost::asio;io_service service;ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);ip::tcp::socket sock(service);sock.async_connect(ep, connect_handler);service.run();void connect_handler(const boost::system::error_code & ec) {// 假如沒有ErrorCode ec,表示成功連線}
跟同步不同的地方在於 socket.connect(endpoint)變成,socket.async_connect(endpoint,回調函數())

async_connet()不同於同步的connect(),它永遠立即返回(但不代表執行完成)並繼續執行service.run()這個迴圈並在這裡被阻塞,直到系統消息通知async_connect,

service.run()迴圈將被掛起,並執行該事件的回調函數,完成後將繼續執行迴圈。


一旦確定成功,回調函數(本例中為connect_handler)將會被呼叫,回調函數會接著確認第一要必要項參數 boost::system::error_code

來確保調用是否成功假如成功,則會開始以異步方式向伺服器寫入資料。



io_serviece是Boost.asio中最重要的一個class.他能跟系統內核打交道,並能等待異步函數調用的完成

以下舉例幾個 io_service的使用方式


1.單線程、單一io_service跟一個回調函數線程

io_service service_;//所有socket的操作將會由這個io_service做處理ip::tcp::socketsock1(service_);ip::tcp::socketsock2(service_);sock1.async_connectep,connect_handler);sock2.async_connect(ep,connect_handler);deadline_timer t(serviece_,boost::posix_time::seconds(5));t.async_wait(timeout_handler);//任何一步操作超過五秒將被視為失敗,並會呼叫timeout_handlerservice_.run();

這個是簡單的調用程式,假如有多個回調函數同時發生,則會發生效能瓶頸,並且會變成序列式的呼叫方式

假如說有某個回調函數會花上時間來執行,其他的回調函數將會被阻塞直到它完成。




2.多線程、單一io_service跟多個回調函數線程

io_serviceservice_;ip::tcp::socketsock1(service_);ip::tcp::socketsock2(service_);sock1.async_connect(ep,connect_handler);sock2.async_connect(ep,connect_handler);deadline_time t(service_,boost::posix_time::seconds(5));t.asyc_wait(timeout_handler);for(int i=0;i<5;<<++i)boost::thread(run_serivice);void run_service(){service_.run();}
這是大部分開發時真正會使用的方式,此處是創建5個線程來等待兩個異步函數的調用,假如說thread1正在執行回調函數,

service_會自動找尋其他4個空閒中的thread來處理接下來的調用。


3.多線程、多io_service跟多個回調函數線程

io_service service_[2];ip::tcp::socket sock1(service_[0]);ip::tcp::socket sock2(service_[1]);sock1.async_connect( ep, connect_handler);sock2.async_connect( ep, connect_handler);deadline_timer t(service_[0], boost::posix_time::seconds(5));t.async_wait(timeout_handler);for ( int i = 0; i < 2; ++i) boost::thread( boost::bind(run_service, i));void run_service(int idx) { service_[idx].run();}
最複雜但最有彈性,當方法二還無法滿足效能上的需求時才會使用這個;連io_serviece管理也多創建出一個實例來。


今天就到這邊吧,預定C++並發編程筆記下一次會記錄有關於boost::asio更多函數的使用方法。

簡單的程式,假如有多個回調函數同時發生,則會發生效能瓶頸,並且會變成序列式的呼叫方式

假如說有某個回調函數會花上時間來執行,其他的回調函數將會被阻塞直到它完成。

0 0
原创粉丝点击