boost.asio包裝類st_asio_wrapper開發教程(2014.5.23更新)(一)-----轉
一:什么是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,就可實現一個簡單的客戶端了,如下:

- //configuration
- #define SERVER_PORT 9527
- #define FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer
- //configuration
- #include "st_asio_wrapper_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_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(1);
- 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里面都有。
from:http://blog.csdn.net/yang79tao/article/details/7724514
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成