本文已于20170903更新完畢,所有boost asio 代碼均為本人手抄。編譯器為vs2013,并且所有代碼已經上傳,本文下方可下載下傳源碼

<a href="https://files.cnblogs.com/files/zhangdongsheng/boost_asio_%E4%BB%A3%E7%A0%81_vs2013%E7%BC%96%E8%AF%91%E6%88%90%E5%8A%9F.rar" target="_blank"> </a>
為了學習boost asio庫,我是從boost的官方boost asio的教程學起的。
每一個示例我都抄寫了一遍以加深記憶,每一個例子我都用自己的話概括一遍,雖然概括的不是很好,代碼覺得難懂的地方我都加注釋。
1.同步使用Timer
本便使用了boost::asio::deadline_timer,這個timer有兩種狀态:過期和不過期。wait函數調用一個過期的timer直接傳回。
2.異步使用Timer
下在示範了使用deadline_timer的asyn_wati函數實作異步等待。但要注意的一點是異步等待必須要調用io.run才可以。而且必須在io.run函數執行之前調用asyn_wait,否則io.run會立即傳回,因為他沒有可以做的事。這說明io.run必須至少有一個等待的,否則它會直接傳回。asio函數保證回調函數執行和io.run所在的線程一樣!
3.為回調函數綁定參數
這個例子一個是說明異步Timer的可持續性問題,也就是在回調中設定Time的逾時時間。另一個說明回調函數參數的綁定 。但是實際發現我官的代碼沒有發生那個重複回調的效果。原因是我隻是調用了expire_at而沒有調用再次等待函數async_wait。這讓我更加明白expires_at這個函數相當于下次觸發的時間。而async_wait送出一個等待申請。
async_wait送出一次,回調函數執行一次,而expire_at設定下次回調函數調用的時間。
4.類成員做為timer的回調函數
這個例子主要示範了,如何綁定一個類成員函數作為一個回調
4.在多線程程式中的同步回調
先前的例子通過io_service.run和同步回調在同一個線程内,正如你所知的那樣,asio保證回調函數隻能被在io_service.run()所在的線程調用 。是以,隻有在一個線程内調用io_service::run保證回調函數不會并發執行。這樣在伺服器程式中有兩個局限性:
1.當回調函數執行時間比較長時響應太慢
2.沒有起到多處理器的優勢
如果你注意到這個局限性,一個可供選擇的方案是建立一個線程池去調用io_service.run()函數,這樣實作的回調的并發,我們需要去同步一個共享變量。
下面的例子使用到了An boost::asio::strand ,他保證這些回調函數通過strans派遣,它可以允許一個回調函數在另一個回調函數執行之前完成。簡單點說,這裡的strand就是讓回調函數不會并發的執行。但是這裡的strand到底的意圖在哪裡?不是要示範多線程執行回調嗎?這裡又做了strand使回調又依次執行好想沒有達到多線程效果
下面有時間研究一下 boost::asio::strand的用法
5.簡單的一個TCP服務端
下面程式示範一個boost做的最簡單的一個服務端程式,用戶端連接配接之後伺服器給用戶端發送一個目前時間的字元串
下面值得一提的是tcp::acceptor,他被封裝為socket的服務端接收器,構造他時需要一個io_service和一個tcp::endpoint。
6.簡單的一個TCP用戶端
7.TCP異步服務端
以上代碼調用異步函數asyn_accept和asyn_write分别進行異步接受socket和異步socket發送。
以上代碼是官方tutorial的代碼,有幾點特别的地方值得學習:
構造函數私有化
一般自己寫代碼構造函數不可能給私有化,而類tcp_connection使用一個靜态類成員函數Create生産一個對象,而使得類的構造函數可以私有。
使用enable_shared_from_this
boost類enable_shared_from_this的好處是避免在類成員函數中傳遞this而傳遞一個shared_ptr智能指針,這樣不用擔心釋放的問題。而在這裡,如果傳指針則有可能所持有的指針指向的對象已經被釋放,如果用shared_ptr則可以保證不被釋放,引用官方的一句話:We will use <code>shared_ptr</code> and <code>enable_shared_from_this</code> because we want to keep the <code>tcp_connection</code> object alive as long as there is an operation that refers to it.
不指定沒有用的參數,有可能注意到handle_write()沒有error和byte_transfered參數,因為body中沒有用到這兩個參數,如果參數不使用可能以移除參數
8.Custom Allocation
以上代碼在調用socket.async_read_some的時候,第二個參數原來是一個Handler,原型如下:
首先:回調用函數應該是一個執行體,也就是std::function,而這裡來一個custom_alloc_handler<Handler>對象,對象也可以當作執行體?
其次:這個函數沒有用到asio_handler_allocate和asio_handler_deallocate,我也不知道如何使用。這個放到以後再研究
經過學習和查詢資訊得出的結果:
異步操作可以增加一個臨時的配置設定對象asio_handler_allocate。因為異步操作有一個handler函數對象,這個臨時對象可以堪稱是與handler函數對象相關聯的。本例中asio_handler_allocate為handler類對象的一個友元成員函數。這樣在配置設定記憶體時,預設就調用此函數進行配置設定記憶體。任何與handler相關聯的臨時對象會在handler執行完之後被析構,而asio_handler_allocate這裡除了size參數可以額外增加參數,例如本例中的this_handler參數一樣,是以這裡允許同一塊記憶體可以被後來的異步操作重複利用,asio_handler_allocate原型如下:
Handler允許有多種形式存在
函數形式
類對象(重載括号運算符)
類成員函數
通過以上知識點,可以清楚知道本例代碼是如何執行的了。
9.Buffers
代碼解析:
本例主要示範了,異步操作中可以自定義的buffer。
以上代碼自定義一個類shared_const_buffer,在調用async_write用這個類對象。async_write有多個重載,這裡主要說示例中用到的重載形式,即:
第二具模闆參數ConstBufferSequence為一個模闆參數,自定義ConstBufferSequence模闆類有一些要求如下 :
在下面要求清單中,X表示為一個包含類型T對象的類。a表示表示一個類型為X的值,u表示一個辨別符
本例中T為boost::asio::const_buffer buffer_,X為本例中的shared_const_buffer。
X::value_type 傳回類型為T,用于表示X實際表示的value_type為T,本例中為boost::asio::const_buffer
X::const_iterator 指向T的疊代器類型,表示iterator類型實際為哪種類型,本例中為 const boost::asio::const_buffer *
X(a) 構造函數
X u(a) 暫時不知如何解釋
(&a)->~X() 暫時不知如何解釋
a.begin() 傳回起始疊代器
a.end() 傳回終止疊代器
10.Chat_message資料包類
這個類比較簡單,他把一個資料包定義為頭和體。頭部是一個整形,代表body的大小。
11.Chat_Server詳解
先上代碼
服務端做異步監聽,當有用戶端到來,把這個用戶端(session) 放到聊天室對象裡,當這個用戶端斷開時,從聊天室用戶端清單裡删除。
這個聊天室實作了一個廣播功能,當用戶端發送消息至伺服器時,伺服器給所有用戶端廣播這條消息,并且聊天室記錄最近用戶端發送到伺服器的消息,當用戶端連接配接到伺服器時,伺服器主動把最近消息記錄發送給這個用戶端。
這裡要注意到一點的是,他的發送是類似消息驅動的形式,就是用一個對象儲存要發送的消息,當發送成功回調OnSend裡發現有未發完的消息時,再骈PostSend。而不是主動發送。我暫時不知道這種做法的意圖。但是可以注意到的一點是這種發送是依次的,也就是PostSend順序是這樣的 PostSend OnSend PostSend OnSend,而我們經常的做法則是PostSend PostSend OnSend OnSend。這個好處不言而喻。提供了一種緩存機制。
12.Chat_Client詳解
這個用戶端沒有什麼特點,最大的特别就是我上節在服務端說到的,消息回調Post機制。
13.echo
echo都是非常簡單的socket示例,暫時不做熬述
14.Futures
知識點:
io_service::work 這是一個很小的輔助類,隻支援構造函數和析構函數。構造一個 work時,outstanding_work_+1,使得io.run在完成異步消息之後判斷outstanding_work_時不為0,因而會使io.run()不至于傳回。通俗的講它就是讓io.run一直運作不退出,隻到work析構。
std::future 他是擷取異步執行函數的傳回值的,相當于你建立了一個線程線程在計算某個結果,你要得到這個結果時,你得同步一下,還要看一下,結果算完了沒有。future就是做這件事的。關于這個std::future我會另外開一篇文章寫一下。這裡有一篇檔案詳細介紹一下這個std::future幹了什麼http://blog.csdn.net/wangshubo1989/article/details/49872199
io.stop 這個函數是告訴io_service要停止 。
18.HttpServer
本例用boost asio 寫了一個簡易http伺服器,與前面的相比新的知識點不多。
下面提供源碼下載下傳:
<a href="https://files.cnblogs.com/files/zhangdongsheng/boost_asio_%E4%BB%A3%E7%A0%81_vs2013%E7%BC%96%E8%AF%91%E6%88%90%E5%8A%9F.rar" target="_blank">源碼下載下傳</a>