一:什麼是st_asio_wrapper
它是一個c/s網絡編程框架,基於對boost.asio的包裝(最低在boost-1.49.0上調試過),目的是快速的構建一個c/s系統;
二:st_asio_wrapper的特色
效率高、跨平臺、徹底異步,固然這是從boost.asio繼承而來;
自動重連,數據透明傳輸,自動解決分包粘包問題(必須使用默認的打包解包器,這一特性表現得與udp同樣);
只支持tcp和udp協議;
三:st_asio_wrapper的大致結構
st_asio_wrapper.h:
編譯器版本測試,更新日誌等;
st_asio_wrapper_base.h:
存放一些全局類、函數、宏以及日誌輸出等;
st_asio_wrapper_timer.h(class st_timer):
定時器類,如下類均須要,除了打包解包器;
st_asio_wrapper_socket.h(class st_socket):
st_tcp_socket和st_udp_socket的基類,主要負責消息派發相關功能;
st_asio_wrapper_tcp_socket.h(class st_tcp_socket):
tcp套接字類,用於tcp數據的收發,從st_socket繼承;
st_asio_wrapper_udp_socket.h(class st_udp_socket):
udp套接字類,用於udp數據的收發,從st_socket繼承;
st_asio_wrapper_packer.h(interface i_packer, class packer):
i_packer是打包器的接口,packer是st_asio_wrapper自帶的打包器;
st_asio_wrapper_unpacker.h(interface i_unpacker, class unpacker):
i_unpacker是解包器的接口,unpacker是st_asio_wrapper自帶的解包器;
st_asio_wrapper_service_pump.h(interface i_service, class st_service_pump):
asio的io_servie包裝類,用於運行st_asio_wrapper的全部service對象(st_server_base, st_sclient, st_tcp_client_base, st_udp_client_base);
st_asio_wrapper_object_pool.h(class st_object_pool):
對象池,從原來的st_server_base抽象出來,供st_server_base和st_client繼承,因而乎,服務端和客戶端(支持多條鏈接的)都有了對象池功能;
st_asio_wrapper_server.h(class st_server_base):
st_server是服務端的服務對象類,用於服務端的監聽、接受客戶端請求等,須要實現i_server接口;
st_asio_wrapper_server_socket.h(interface i_server, class st_server_socket):
前者用於從st_server獲取必要的信息,和調用必要的接口;後者從st_tcp_socket繼承,用於服務端的數據收發;
st_asio_wrapper_connector.h(class st_connector):
從st_tcp_socket繼承,實現鏈接服務器(包括重連)邏輯;
st_asio_wrapper_client.h(class st_sclient_base, class st_client_base):
client相關的公共邏輯,好比遍歷等,被st_tcp_client_base和st_udp_client_base繼承;
st_asio_wrapper_tcp_client.h(class st_tcp_sclient, class st_tcp_client_base):
前者從st_connector繼承,只支持一條鏈接,後者支持任意多條鏈接,他們實現了一些邏輯,以便被st_service_pump調用;
st_asio_wrapper_udp_client.h(class st_udp_sclient, class st_udp_client_base):
基於udp套接字的service對象;
st_asio_wrapper_ssl.h(class st_ssl_connector_base, class st_ssl_object_pool, class st_ssl_server_socket_base, class st_ssl_server_base):
全部st_asio_wrapper庫支持的ssl相關的類庫;
源代碼及例程下載地址:
命令行:svn checkout http://st-asio-wrapper.googlecode.com/svn/trunk/ st-asio-wrapper-read-only
若是從svn客戶端界面上打開,則只輸入http://st-asio-wrapper.googlecode.com/svn/trunk/到地址欄便可
git:https://github.com/youngwolf-project/st_asio_wrapper/,另外,個人資源裏面也有下載,但不是最新的。
QQ交流羣:198941541
其中include文件夾裏面是st_asio_wrapper的全部類、asio_client和asio_server配合用於演示最簡單的數據收發、file_server和file_client用於演示文件傳送、test_client和asio_server配合用於性能測試、udp_client演示udp通訊,他們都基於st_asio_wrapper,能夠當作是sample;
類庫(包括demo)在vc下有幾個警告,都可安全忽略;
類庫裏面大量使用了c++0x特性,主要有:range-based for loop、lambda表達式、nullptr、auto、右值引用、泛型begin()和end()等;所以至少須要vc2010及其以上版本的編譯器,或者gcc4.6以上;
在vc2010和gcc4.6以前的編譯器版本中,請使用兼容版本,在compatiable_edition文件夾裏面(注意兼容版本的效率並不比普通版本低,甚至略高);
推薦在能用的狀況下,仍是用普通版本(或者說標準版本,這是相對於兼容版本而言的),雖然效率沒有提升,但你用在一個複雜的工程中時,可能普通版本效率會高,由於相同的代碼下,c++0x的效率要廣泛的高一些,在st_asio_wrapper裏面沒有表現出來,是由於我特別的對兼容版本作過優化(並且個人使用也有限,好比有些沒法優化的地方,我恰好不須要使用,就躲過去了);
須要開發者本身編譯boost庫,大概須要boost.system和boost.thread兩個庫。
五:開發教程(客戶端)
客戶端直接#include st_asio_wrapper_client.h,就可實現一個簡單的客戶端了,以下:c++
//configuration #define SERVER_PORT 9527 #define FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer //configuration #include "../include/st_asio_wrapper_tcp_client.h" using namespace st_asio_wrapper; #define QUIT_COMMAND "quit" #define RESTART_COMMAND "restart" #define RECONNECT_COMMAND "reconnect" #define SUSPEND_COMMAND "suspend" #define RESUME_COMMAND "resume" int main() { std::string str; st_service_pump service_pump; st_tcp_sclient client(service_pump); //there is no corresponding echo client demo as server endpoint //because echo server with echo client made dead loop, and occupy almost all the network resource client.set_server_addr(SERVER_PORT + 100, SERVER_IP); // client.set_server_addr(SERVER_PORT, "::1"); //ipv6 // client.set_server_addr(SERVER_PORT, "127.0.0.1"); //ipv4 service_pump.start_service(); while(service_pump.is_running()) { std::cin >> str; if (str == QUIT_COMMAND) service_pump.stop_service(); else if (str == RESTART_COMMAND) { service_pump.stop_service(); service_pump.start_service(1); } else if (str == RECONNECT_COMMAND) client.graceful_close(true); //the following two commands demonstrate how to suspend msg sending, no matter recv buffer been used or not else if (str == SUSPEND_COMMAND) client.suspend_send_msg(true); else if (str == RESUME_COMMAND) client.suspend_send_msg(false); else client.safe_send_msg(str); } } //restore configuration #undef SERVER_PORT #undef FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer //restore configuration
以上例子中,客戶端從控制檯接收數據,調用safe_send_msg發送數據;當收到數據時,會輸出到控制檯(st_tcp_socket或者st_udp_socket實現);
其中,start_service開啓服務,stop_service結束服務(退出時必須明確調用),is_running判斷服務的運行狀態;若是想修改服務端地址,則在調用start_service以前調用set_server_addr函數;
stop_service以後,可再次調用start_service開啓服務;
不stop_service而直接想重鏈接,則以true調用st_connector的force_close或者graceful_close;
固然,通常來講,客戶端不會只把收到的數據顯示到控制檯這麼簡單,此時須要從st_tcp_sclient或者st_udp_sclient派生一個類(若是你有多條鏈接,則從st_connector或者st_udp_socket派生一個類,並用st_tcp_client或者st_udp_client來管理它,這個請參考test_client這個demo,它支持多條鏈接),而後有兩種方法供你選擇,一:重寫on_msg並在裏面直接返回true(或者定義FORCE_TO_USE_MSG_RECV_BUFFER宏,至於爲何要這樣,你須要看完全部st_asio_wrapper的一系列教程共四篇),而後再重寫on_msg_handle並在裏面作消息處理;二:重寫on_msg,並在裏面作消息處理,而後返回false。這兩種方式的區別是:前者不會阻塞消息的接收,後者會,好比你的消息處理須要1秒,那麼在這1秒鐘以內,前者與接收消息並行,後者則不能接受消息,直到消息處理結束。另外一個區別是:前者須要接收緩存,後者不須要。固然,這裏說的阻塞,是指對當前套接字的阻塞,與其它套接字無關,好比在服務端,有兩個套接字,當你處理套接字1的消息時,不管你用前面的哪種方法,都不可能阻塞套接字2的消息接收。關於這個話題,請參看教程第四篇;
在消息發送成功以後,你有一次機會獲得通知,那就是重寫on_msg_send函數,它的參數就是這個消息(注意,是打包後的);
每調用一次send_msg或者safe_send_msg,對方一定收到一次如出一轍的數據,二次開發者不用再考慮分包粘包問題(必須使用默認的打包解包器),這一特色你徹底能夠把它當成udp的行爲;
st_socket裏面有發送消息緩存,因此當二次開發者有數據須要發送的時候,能夠隨時調用send_msg(注意緩存滿的問題,safe_send_msg保證數據發送成功,當緩存滿時會等待)而不用關心當前鏈接是否已經創建,它會在條件適當的時候,爲你發送數據。
你可能須要修改的宏有如下幾類:
1.全局宏,服務端客戶端均須要:
UNIFIED_OUT_BUF_NUM:unified_out類使用的緩存空間大小,默認2048;
MAX_MSG_LEN:消息最大長度(打包後的,拿默認的packer來講,它最大僅支持3998消息長度,由於還有一個2字節的包頭),默認4000。對於默認打包器解包器,這個長度範圍只能是1至(65535-2),由於包頭只用了兩個字節的緣故,若是想要超過這個限制,可定義HUGE_MSG宏;
HUGE_MSG:開啓大消息支持,默認關閉。注意,大消息會佔用大內存,請看asio_client這個demo,裏面有演示用法(註釋狀態),以及對於佔用大內存的解釋;
MAX_MSG_NUM:每一個st_socket消息緩存最大消息條數(接收和發送緩存共用,因此總的最大消息條數是2倍的MAX_MSG_NUM),默認1024;
ENHANCED_STABILITY:加強的健壯性,若是開啓這個宏,全部service對象都會在最外層(io_service.run)包一層try catch,以增長健壯性,固然,增長try是會有效率損失的,本宏默認不開啓;
FORCE_TO_USE_MSG_RECV_BUFFER:始終使用消息接收緩存,這個是編譯期優化,前面說了,on_msg()返回true表明使用消息接收緩存,若是你的on_msg()永遠返回true,則能夠開啓這個宏,那麼st_tcp_socket或者st_udp_socket將再也不調用on_msg()(根本不存在這個虛函數了)而是直接將消息放入消息接收緩存,這樣能夠提升一些效率,默認不開啓本宏;
NO_UNIFIED_OUT:讓st_asio_wrapper裏面的全部輸出失效;
CUSTOM_LOG:自定義輸出,此時你須要提供5個日誌函數,函數名和簽名參看unified_out類,且要麼是靜態的,要麼是全局的。
DEFAULT_PACKER:自定義打包器,它是一個類名,必須提供默認構造函數(即沒有參數的構造函數)。
DEFAULT_UNPACKER:自定義解包器,它是一個類名,必須提供默認構造函數(即沒有參數的構造函數)。
ST_SERVICE_THREAD_NUM:IO線程數量,用於運行io_service.run函數。
MAX_OBJECT_NUM:對象池最多支持的對象數量,默認4096;
REUSE_OBJECT:是否開啓對象池,若是開啓,當建立新對象時,將嘗試使用已經被關閉的對象,此時將不會自動定時的釋放被關閉的對象鏈表,請參看SOCKET_FREE_INTERVAL宏,默認不開啓本宏;
SOCKET_FREE_INTERVAL:說這個宏以前,要說一下st_object_pool的內部工做原理:當調用del_object的時候(st_server_socket在on_recv_error裏面的默認行爲),st_object_pool的做法並非刪除這個對象,而是把這個對象移動到另一個鏈表裏面,這個鏈表裏面的對象會被每SOCKET_FREE_INTERVAL秒遍歷一次,以找到已經關閉超過CLOSED_SOCKET_MAX_DURATION秒鐘的對象,而後真正的從內存中釋放它,緣由是當del_object的時候,可能還有其它的異步操做還沒完成,或者完成了,但還在隊列中沒有被分發,若是此時從內存中釋放對象,那麼後面的異步回調的時候,可能會出現內存訪問越界。這個問題能夠經過爲每個異步調用都綁定一個指向本對象this指針的shared_ptr作爲參數,但過分使用shared_ptr會影響到效率。單位爲秒,默認10秒。若是開啓了REUSE_OBJECT,則本宏根本不使用(也就不存在定時遍歷了),由於被關閉的對象已經放入對象池,等着被重用,不能釋放;
AUTO_CLEAR_CLOSED_SOCKET:服務端是否認時的循環的調用clear_all_closed_object()以清除已經被關閉的套接字,若是你不方便調用del_object,則對象池裏面將會累積愈來愈多的被關閉了的對象(若是有鏈接出錯,或者退出的話),你能夠打開這個宏,讓st_object_pool爲你定時的作這些清除工做;注意,若是對象鏈表很是大,遍歷鏈表是會影響效率的;遍歷的時間間隔由CLEAR_CLOSED_SOCKET_INTERVAL定義,默認不開啓本宏;
CLEAR_CLOSED_SOCKET_INTERVAL:定時調用clear_all_closed_object()間隔,單位爲秒,默認60秒,若是未開啓AUTO_CLEAR_CLOSED_SOCKET,則本宏根本不使用(也就不存在定時調用clear_all_closed_object()了);
CLOSED_SOCKET_MAX_DURATION:關閉鏈接多少秒鐘以後,能夠安全釋放對象或者重用對象(取決於REUSE_OBJECT是否被定義,定義了就是重用,不然釋放),默認爲5秒。
2.tcp客戶端專用宏:
GRACEFUL_CLOSE_MAX_DURATION:優雅關閉時,最長等待時間,單位爲秒,默認5。
SERVER_IP:服務器IP地址,用字符串形式表示,默認"127.0.0.1";
SERVER_PORT:服務器端口,默認5050;
RE_CONNECT_INTERVAL:當鏈接服務器失敗時,延時多長時間重連,單位是毫秒,默認500毫秒;
RE_CONNECT_CONTROL:打開此宏以後,能夠控制重鏈接次數,運行時也可修改。
3.tcp服務端專用宏:
SERVER_PORT:服務器端口(服務器IP若是要設置的話,只能調用set_server_addr接口,不能經過宏來實現),默認5050;
TCP_DEFAULT_IP_VERSION:在不指定服務端IP時,經過這個宏指定IP協議的版本(v4仍是v6,取值分別是boost::asio::ip::tcp::v4()和boost::asio::ip::tcp::v6()),若是指定了IP,則版本從ip地址中分析得來;
ASYNC_ACCEPT_NUM:最多同時投遞多少個異步accept調用,默認1;
NOT_REUSE_ADDRESS:關閉端口重用,udp也用使用此宏。
4.udp客戶端專用宏:
UDP_DEFAULT_IP_VERSION:在不指定IP時,經過這個宏指定IP協議的版本(v4仍是v6,取值分別是boost::asio::ip::udp::v4()和boost::asio::ip::udp::v6()),若是指定了IP,則版本從ip地址中分析得來;
以上宏均可以按工程爲單位來修改,你只須要在include相應st_asio_wrapper相關頭文件以前,定義這些宏便可,具體例子demo裏面都有。git
boost.asio包裝類st_asio_wrapper開發教程(2015.6.5更新)(一)github
文檔和demo編程
https://github.com/youngwolf-project/st_asio_wrapper/緩存