C/S框架 st_asio_wrapper 開發教程——瞭解st_asio_wrapper(2019.10.17更新)

一:什麼是st_asio_wrapper & ascs

它是一個c/s網絡編程框架,基於對boost.asio的包裝(最低要求:boost-1.49.0 + gcc-3.4.6(仍未找到最低支持版本,缺少測試環境) / Clang(未尋找最低支持版本,只嘗試過3.4.1——一個很新的版本) / vc2008),目的是快速的構建一個c/s系統;ascs和st_asio_wrapper功能完全一樣,只是ascs不依賴boost(但可以與boost一起使用),且需要c++11的支持(對於vc來說,至少需要vc2013),在滿足ascs最低依賴條件時,我推薦使用ascs,它在編譯和運行速度上都要快於st_asio_wrapper。

二:st_asio_wrapper的特點

效率高、跨平臺、完全異步,當然這是從boost.asio繼承而來;
自動重連,數據透明傳輸,自動解決分包粘包問題(必須使用默認的打包解包器,這一特性表現得與udp一樣);
內部提供緩存支持;
支持運行時替換打包解包器;
支持ssl。
支持VC, gcc和clang。
原生支持異步消息收發,支持同步消息收發(用異步模擬)。
只支持tcp和udp協議;

三:st_asio_wrapper的大體結構

config.h:
編譯器版本測試,更新日誌等以及所有支持的宏(如果某個宏默認不開啓,也會在這個文件裏面,只是是註釋狀態);

base.h:
存放一些接口(比如打包解包器接口)、全局類、輔助類、函數以及日誌輸出等;

service_pump.h(class service_pump):
asio的io_servie(又名io_context)包裝類,用於運行st_asio_wrapper的所有service對象(tcp::server_base, tcp::single_client_base, tcp::multi_client_base, udp::single_socket_service_base, udp::multi_socket_service_base, ssl::server_base, ssl::single_client_base, ssl::multi_client_base);

executor.h(class executor), tracked_executor.h(class tracked_executor):
最頂級父類,主要工作是hook異步調用(以防止異步調用還未回調或者放棄的時候就釋放或者重用對象);

timer.h(class timer,派生於executor或者tracked_executor類):
定時器類;

socket.h(class socket,派生於timer類):
tcp::socket_base和udp::socket_base的基類,主要負責消息收發邏輯(不做實際收發),消息派發、啓停等相關功能;

tcp/socket.h(class socket_base,派生於socket類):
tcp套接字類,用於tcp數據的收發;

udp/socket.h(class socket_base,派生於socket類):
udp套接字類,用於udp數據的收發;

object_pool.h(class object_pool,派生於timer類):
對象池,創建和重用對象,維護對象生命週期;

tcp/server.h(class server_base,派生於object_pool類):
服務端對象,用於服務端的監聽、接受客戶端請求等;

tcp/server_socket.h(class server_socket_base,派生於tcp::socket_base類):
實現服務端相關邏輯;

tcp/client_socket.h(class client_socket_base,派生於tcp::socket類):
實現客戶端相關邏輯(比如連接與重連等);

socket_service.h(class single_socket_service,派生於tcp或者udp的socket_base類, class multi_socket_service,派生於object_pool類):
可以被service_pump類管理的,包涵單個socket和多個socket對象的service類;

tcp/client.h(class single_client_base,派生於single_socket_service類,class multi_client_base,派生於multi_socket_base類):
tcp單連接和多連接客戶端;

udp/socket_service.h(class single_socket_service_base派生於single_socket_service類,class multi_socket_service_base,派生於multi_socket_base類):
udp單套接字和多套接字服務;

tcp/ssl/ssl.h(client_socket_base, server_socket_base, server_base, single_client_base, multi_client_base):
st_asio_wrapper庫支持的ssl相關的所有類;

ext目錄:
主要存放各種各樣的打包解包器,輔助類,以及一些方便的定義,比如把需要模板參數的client_socket_base類定義成不需要模板參數的client_socket類(所有以_base結尾的類,都有一個typedef,以定義一個不帶_base結尾,且不帶任何模板參數的類)等;

四:源代碼及demo下載地址

git:https://github.com/youngwolf-project/st_asio_wrapper/,ascs位置與st_asio_wrapper平級。
QQ交流羣:198941541 這裏面有各個版本供下載。
其中include文件夾裏面是st_asio_wrapper的所有類、client和echo_server配合用於演示最簡單的數據收發、file_server和file_client用於演示文件傳送、echo_client和echo_server配合用於性能測試、pingpong_client和pingpong_server配合用於乒乓測試、concrrent_client和concurrent_server配合用於併發測試、udp_test演示udp通信、ssl_test演示ssl通信,他們都基於st_asio_wrapper;

        推薦在可能的情況下,儘量用ascs,它不依賴boost,也就不需要編譯boost這個龐大的庫,同時編譯速度和運行速度都優於st_asio_wrapper,st_asio_wrapper主要用於老的編譯系統,比如說歷史遺留工程;

五:開發教程(客戶端)

客戶端直接#include ext/tcp.h,就可實現一個簡單的客戶端了,如下(摘自client,可能會有改動,以包裏面的demo爲準):

//configuration
#define ST_ASIO_SERVER_PORT 9527
#define ST_ASIO_DEFAULT_UNPACKER non_copy_unpacker
//configuration

#include "../include/ext/tcp.h"
using namespace st_asio_wrapper::ext::tcp;

#define QUIT_COMMAND	"quit"
#define RESTART_COMMAND	"restart"
#define RECONNECT_COMMAND "reconnect"

int main(int argc, const char* argv[])
{
	service_pump sp;
	single_client client(sp);

	if (argc > 2)
		client.set_server_addr(atoi(argv[1]), argv[2]);
	else if (argc > 1)
		client.set_server_addr(atoi(argv[1]), ST_ASIO_SERVER_IP);
	else
		client.set_server_addr(ST_ASIO_SERVER_PORT + 100, ST_ASIO_SERVER_IP);

	sp.start_service();
	while(sp.is_running())
	{
		std::string str;
		std::cin >> str;
		if (QUIT_COMMAND == str)
			sp.stop_service();
		else if (RESTART_COMMAND == str)
		{
			sp.stop_service();
			sp.start_service();
		}
		else if (RECONNECT_COMMAND == str)
			client.graceful_shutdown(true);
		else
			client.safe_send_msg(str, false);
	}

	return 0;
}

以上例子中,客戶端從控制檯接收數據,調用safe_send_msg發送數據;當收到數據時,會輸出到控制檯(st_asio_wrapper::socket實現);

        其中,start_service開啓服務,stop_service結束服務(退出時必須明確調用),is_running判斷服務的運行狀態;如果想修改服務端地址,則在調用start_service之前調用set_server_addr函數;
        stop_service之後,可再次調用start_service開啓服務;
        不stop_service而直接想重連接,則以true調用tcp::client_socket_base的force_shutdown或者graceful_shutdown;
      當然,一般來說,客戶端不會只把收到的數據顯示到控制檯這麼簡單,此時需要從tcp::single_client_base或者udp::single_service_base派生一個類(如果你有多條連接,則從tcp::client_socket_base或者udp::socket_base派生一個類,並用tcp::multi_client_base或者udp::multi_service_base來管理它,這個請參考echo_client這個demo,它支持多條連接),然後重寫on_msg_handle並在裏面做消息處理,如果消息被處理,請返回true,否則消息將會被延時一小段時間之後,繼續派發(仍然通過這個函數)。
        在消息發送成功之後,你有一次機會得到通知,那就是重寫on_msg_send函數,它的參數就是這個消息(注意,是打包後的);
        每調用一次消息發送函數,對方必定收到一次一模一樣的數據,二次開發者不用再考慮分包粘包問題(必須使用我提供的打包解包器),這一特點你完全可以把它當成udp的行爲;
        socket裏面有發送消息緩存,所以當二次開發者有數據需要發送的時候,可以隨時發送(注意緩存滿的問題,safe_send_msg保證數據發送成功,當緩存滿時會等待)而不用關心當前連接是否已經建立,它會在條件適當的時候,爲你發送數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章