<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    boost.asio包裝類st_asio_wrapper開發教程(2014.5.23更新)(一)-----轉

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    一:什么是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,就可實現一個簡單的客戶端了,如下:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. //configuration  
    2. #define SERVER_PORT     9527  
    3. #define FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer  
    4. //configuration  
    5.   
    6. #include "st_asio_wrapper_client.h"  
    7. using namespace st_asio_wrapper;  
    8.   
    9. #define QUIT_COMMAND    "quit"  
    10. #define RESTART_COMMAND "restart"  
    11. #define RECONNECT_COMMAND "reconnect"  
    12. #define SUSPEND_COMMAND "suspend"  
    13. #define RESUME_COMMAND  "resume"  
    14.   
    15. int main() {  
    16.     std::string str;  
    17.     st_service_pump service_pump;  
    18.     st_sclient client(service_pump);  
    19.     //there is no corresponding echo client demo as server endpoint  
    20.     //because echo server with echo client made dead loop, and occupy almost all the network resource  
    21.   
    22.     client.set_server_addr(SERVER_PORT + 100, SERVER_IP);  
    23. //  client.set_server_addr(SERVER_PORT, "::1"); //ipv6  
    24. //  client.set_server_addr(SERVER_PORT, "127.0.0.1"); //ipv4  
    25.   
    26.     service_pump.start_service(1);  
    27.     while(service_pump.is_running())  
    28.     {  
    29.         std::cin >> str;  
    30.         if (str == QUIT_COMMAND)  
    31.             service_pump.stop_service();  
    32.         else if (str == RESTART_COMMAND)  
    33.         {  
    34.             service_pump.stop_service();  
    35.             service_pump.start_service(1);  
    36.         }  
    37.         else if (str == RECONNECT_COMMAND)  
    38.             client.graceful_close(true);  
    39.         //the following two commands demonstrate how to suspend msg sending, no matter recv buffer been used or not  
    40.         else if (str == SUSPEND_COMMAND)  
    41.             client.suspend_send_msg(true);  
    42.         else if (str == RESUME_COMMAND)  
    43.             client.suspend_send_msg(false);  
    44.         else  
    45.             client.safe_send_msg(str);  
    46.     }  
    47. }  
    48. //restore configuration  
    49. #undef SERVER_PORT  
    50. #undef FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer  
    51. //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中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全