1、HPSocket介紹linux
HP-Socket是一套通用的高性能TCP/UDP/HTTP 通訊框架,包含服務端組件、客戶端組件和Agent組件,普遍適用於各類不一樣應用場景的TCP/UDP/HTTP通訊系統,提供C/C++、C#、Delphi、E(易語言)、Java、Python等編程語言接口。HP-Socket對通訊層徹底封裝,應用程序沒必要關注通訊層的任何細節;HP-Socket提供基於事件通知模型的API接口,能很是簡單高效地整合到新舊應用程序中。
c++
1.編譯git
下載Hp-socket庫:github
git clone https://github.com/ldcsaa/HP-Socket.git
這個庫有多個系統的版本,咱們這裏選用linux分析就行了。因此進入到Linux下,看readme大概知道編譯流程。編程
./compile.sh sudo ./install.sh
大概就是分兩個腳本,一個編譯腳本和一個安裝腳本。-h參數能夠分別看到他們的使用說明。ubuntu
$ ./compile.sh -h Usage: compile.sh [...O.P.T.I.O.N.S...] ----------------------+------------------------------------------------- -d|--with-debug-lib : compile debug libs (default: true) -j|--use-jemalloc : use jemalloc in release libs : (x86/x64 default: true, ARM default: false) -u|--udp-enabled : enable UDP components (default: true) -t|--http-enabled : enable HTTP components (default: true) -s|--ssl-enabled : enable SSL components (default: true) -z|--zlib-enabled : enable ZLIB related functions (default: true) -i|--iconv-enabled : enable ICONV related functions (default: true) -c|--compiler : compiler (default: g++) -p|--platform : platform: x86 / x64 / ARM : (default: current machine arch platform) -e|--clean : clean compilation intermediate temp files -r|--remove : remove all compilation target files -v|--version : print hp-socket version -h|--help : print this usage message ----------------------+-------------------------------------------------
大概就是選擇某個模塊進行編譯。網絡
看看腳本邏輯框架
# 1.首先加載script/env.sh腳本里的變量和函數 source $PACKAGE_PATH/$SCRIPT_DIR/env.sh # 2.解析參數:設置對應的編譯模塊的變量值並獲得一個控制狀態ACTION_NAME parse_args "$@" # 3.顯示上一步解析獲得的配置結果 print_config # 4.不一樣action的操做 if [ $EXEC_FLAG -eq 1 ]; then do_clean elif [ $EXEC_FLAG -eq 2 ]; then do_remove else do_build
通常狀況下咱們用的是編譯,因此就是do_build函數socket
HPSOCKET_LIB_NAME=hpsocket HPSOCKET4C_LIB_NAME=hpsocket4c do_build() { # 設置一些編譯的變量 C_LAN_OPTS="-c -x c -I $DEPT_INC_DIR -Wall -Wswitch -Wno-deprecated-declarations -Wempty-body -Wconversion -Wreturn-type -Wparentheses -Wno-pointer-sign -Wno-format -Wuninitialized -Wunreachable-code -Wunused-function -Wunused-value -Wunused-variable -fno-strict-aliasing -fpic -fvisibility=hidden -fexceptions -std=c11" CPP_LAN_OPTS="-c -x c++ -I $DEPT_INC_DIR -Wall -Wno-class-memaccess -Wno-reorder -Wswitch -Wno-deprecated-declarations -Wempty-body -Wconversion -Wreturn-type -Wparentheses -Wno-format -Wuninitialized -Wunreachable-code -Wunused-function -Wunused-value -Wunused-variable -fno-strict-aliasing -fpic -fthreadsafe-statics -fvisibility=hidden -fexceptions -frtti -std=c++14" LINK_OPTS="-Wl,--no-undefined -Wl,-L$DEPT_LIB_DIR -L$DEPT_LIB_DIR -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -shared -Wl,-Bsymbolic" RELEASE_CFG_OPTS="-g0 -O3 -fomit-frame-pointer -DNDEBUG" DEBUG_CFG_OPTS="-g2 -gdwarf-2 -O0 -fno-omit-frame-pointer -DDEBUG -D_DEBUG" if [ -d $HPSOCKET_LIB_TARGET_DIR ]; then rm -rf $HPSOCKET_LIB_TARGET_DIR fi if [ -d $HPSOCKET4C_LIB_TARGET_DIR ]; then rm -rf $HPSOCKET4C_LIB_TARGET_DIR fi # 編譯 do_compile $HPSOCKET_LIB_NAME $CFG_RELEASE do_compile $HPSOCKET4C_LIB_NAME $CFG_RELEASE if [ $WITH_DGBUG_LIB -eq 1 ]; then do_compile $HPSOCKET_LIB_NAME $CFG_DEBUG do_compile $HPSOCKET4C_LIB_NAME $CFG_DEBUG fi update_hp_def } do_compile() { _LIB_NAME=$1 _CFG_NAME=$2 parse_compile_args do_compile_step_1 do_compile_step_2 do_compile_step_3 } #這個函數大概就是遞歸編譯生成一堆*.o文件 do_comepile_file() { local _CMD="$CC $_LAN_OPTS $_FULL_FILE_NAME $_CFG_OPTS $_CL_OPTS -o $_OBJ_TARGET_DIR/ $_OBJ_NAME" $_CMD } #這個函數鏈接.o生成.so庫 do_compile_step_2() { local _LIB_FILE_NAME="lib$_LIB_NAME$_LIB_NAME_SUFFIX.so" local _SONAME_OPT="-Wl,-soname,$_LIB_FILE_NAME.$VER_MAJOR" local _OBJ_TARGET_DIR=$_LIB_TARGET_DIR/$OBJ_DIR/$_CFG_NAME local _OBJ_FILES=($(find $_OBJ_TARGET_DIR -name *.o | xargs ls)) local _CMD="$CC -o $_LIB_TARGET_DIR/$_LIB_FILE_NAME $LINK_OPTS $_SONAME_OPT ${_OBJ_FILES[@]} $_LN_OPTS" echo "> $_CMD" } #調用 post-link.sh腳本打包.a庫 do_compile_step_3() { local _LIB_FILE_NAME="lib$_LIB_NAME$_LIB_NAME_SUFFIX" local _LIB_PATH=$PACKAGE_PATH/$_LIB_TARGET_DIR local _CMD="$SCRIPT_DIR/post-link.sh $_AR_FLAG $_LIB_PATH $_LIB_FILE_NAME $PLATFORM $_CFG_NAME $VER_MAJOR $VER_MINOR $VER_REVISE" echo "> $_CMD" $_CMD }
install.sh就不說了。無非就是將庫拉倒系統目錄或者指定目錄,把.h拉到系統目錄中去。編程語言
parse_args "$@" print_config if [ $IS_UNINSTALL -eq 0 ]; then do_install else do_uninstall fi ldconfig > /dev/null 2>&1 do_install() { mkdir -p $PREFIX_PATH/$DEST_LIB_DIR # copy *.a cp_lib_a $HPSOCKET_LIB_TARGET_DIR cp_lib_a $HPSOCKET4C_LIB_TARGET_DIR # copy *.so cp_lib_so $HPSOCKET_LIB_TARGET_DIR cp_lib_so $HPSOCKET4C_LIB_TARGET_DIR mkdir -p $PREFIX_PATH/$DEST_INC_DIR # copy include dir cp_inc $INC_DIR $PREFIX_PATH/$DEST_INC_DIR if [[ $INSTALL_DEMO -eq 1 && -d $DEM_DIR/$PLATFORM && "$(ls -A $DEM_DIR/$PLATFORM)" != "" ]]; then # copy demo .exe files mkdir -p $PREFIX_PATH/$DEST_BIN_DIR cp_bin_exe # copy demo ssl cert files mkdir -p $PREFIX_PATH/$DEST_BIN_DIR/$DEST_CER_DIR cp_bin_cert fi }
至此,庫的編譯就完成了。
2.demo的編譯
庫的應用代碼在demo目錄下,demo這裏是用sln組織的。
我以前用testecho-http這個demo來學習這個庫的使用。
但這裏有個大坑,我實際編譯的時候重寫成makefile,死活告訴我連接不到某幾個方法,但我已經加入庫了。
後來知道是爲何了,用
nm libsocket.so | grep 連接不到的函數名
發現前面的是小寫?而後幫助文檔裏有句話叫作
If the symbol is loacal(no-external), the symbol’s type is instead represented by the corresponding lowercase letter.
因此就是不能調用了哦。
而後這裏有幾種解決方法:
2、使用
HP-Socket 官方庫項目的地址
https://github.com/ldcsaa/HP-Socket
環境:ubuntu
本文基於其readme中的C++程序來作分析
git中提供的《HP-Socket網絡通訊框架開發指南》仍是須要反覆好好看的
1.工做流程
1)建立監聽器
2)建立通訊組件(同時綁定監聽器)
3)啓動通訊組件
4)鏈接到目標主機(Agent組件)
5)處理通訊事件(OnConnect/OnReceive/OnClose等)
6)中止通訊組件(可選:在第7步銷燬通訊組件時會自動中止組件)
7)銷燬通訊組件
8)銷燬監聽器
示例代碼 #include <hpsocket/HPSocket.h> /* Listener Class */ class CListenerImpl : public CTcpPullServerListener { public: // 5. process network events virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen); virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient); virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID); virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength); virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength); virtual EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode); virtual EnHandleResult OnShutdown(ITcpServer* pSender); }; int main(int argc, char* const argv[]) { // 1. Create listener object CListenerImpl s_listener; // 2. Create component object (and binding with listener object) CTcpPullServerPtr s_pserver(&s_listener); // 3. Start component object if(!s_pserver->Start("0.0.0.0", 5555)) exit(1); /* wait for exit */ // ... ... // 6. (optional) Stop component object s_pserver->Stop(); return 0; // 7. Destroy component object automatically // 8. Destroy listener object automatically }
這裏首先是兩點
a.建立監聽器 CListenerImpl s_listener;
b.建立通訊組件(同時綁定監聽器) CTcpPullServerPtr s_pserver(&s_listener);
後續的通訊的啓動、配置等功能,均是經過 s_pserver 來進行的
2.關於 CListenerImpl
class CListenerImpl : public CTcpPullServerListener { public: // 5. process network events virtual EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen); virtual EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient); virtual EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID); virtual EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength); virtual EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength); virtual EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode); virtual EnHandleResult OnShutdown(ITcpServer* pSender); };
1)其中OnPrepareListen等方法,須要本身去具體實現,他們分別會在各自OnXXXX的狀況下觸發
2)關於基類 CTcpPullServerListener
在 Socketinterface.h 中 /************************************************************************ 名稱:PUSH 模型服務端 Socket 監聽器抽象基類 描述:定義某些事件的默認處理方法(忽略事件) ************************************************************************/ class CTcpServerListener : public ITcpServerListener /************************************************************************ 名稱:PULL 模型服務端 Socket 監聽器抽象基類 描述:定義某些事件的默認處理方法(忽略事件) ************************************************************************/ class CTcpPullServerListener : public CTcpServerListener
逐級向上,此處能夠結合pdf中 Server組件接口去看
3.關於 CTcpPullServerPtr
一樣咱們能夠跟蹤到
在HPSocket.h中 typedef CHPSocketPtr<ITcpPullServer, ITcpServerListener, TcpPullServer_Creator> CTcpPullServerPtr;
其實此處有不少相似的
這裏咱們就會了解到,其實(在HPSocket。h開頭)具體的使用方法在開頭作了說明
Usage: 方法一: -------------------------------------------------------------------------------------- 0. 應用程序包含 HPTypeDef.h / SocketInterface.h / HPSocket.h 頭文件 1. 調用 HP_Create_Xxx() 函數建立 HPSocket 對象 2. 使用完畢後調用 HP_Destroy_Xxx() 函數銷燬 HPSocket 對象 方法二: -------------------------------------------------------------------------------------- 0. 應用程序包含 SocketInterface.h 和 HPSocket.h 頭文件 1. 建立 CXxxPtr 智能指針,經過智能指針使用 HPSocket 對象 Release: <-- 動態連接庫 --> 1. x86/libhpsocket.so - (32位/MBCS/Release) 2. x86/libhpsocket_d.so - (32位/MBCS/DeBug) 3. x64/libhpsocket.so - (64位/MBCS/Release) 4. x64/libhpsocket_d.so - (64位/MBCS/DeBug) <-- 靜態連接庫 --> 1. x86/static/libhpsocket.a - (32位/MBCS/Release) 2. x86/static/libhpsocket_d.a - (32位/MBCS/DeBug) 3. x64/static/libhpsocket.a - (64位/MBCS/Release) 4. x64/static/libhpsocket_d.a - (64位/MBCS/DeBug)
這裏使用的是方法二,也就是CXxxPtr 智能指針。
HP-Socket 的 TCP 組件支持 PUSH、 PULL 和 PACK 三種接收模型
一、PUSH 模型:組件接收到數據時會觸發監聽器對象的 OnReceive(pSender, dwConnID,pData, iLength) 事件,把數據「推」給應用程序。 二、 PULL 模型: 組件接收到數據時會觸發監聽器對象的 OnReceive(pSender, dwConnID,iTotalLength) 事件,告訴應用程序當前已經接收到多少數據,應用程序檢查數據的長度,若是知足須要則調用組件的 Fetch(dwConnID, pData, iDataLength) 方法把須要的數據「拉」出來。 三、 PACK 模型: PACK 模型系列組件是 PUSH 和 PULL 模型的結合體,應用程序沒必要處理分包(如: PUSH)與數據抓取(如: PULL), 組件保證每一個 OnReceive 事件都向應用程序提供一個完整數據包。
對於CXxxPtr 智能指針的使用,以CTcpServerPtr爲例,咱們能夠看到有以下方法
typedef CHPSocketPtr<ITcpServer, ITcpServerListener, TcpServer_Creator> CTcpServerPtr; 下面考察主要的 ITcpServer
以其實對於通訊socket的啓動關閉設置等功能都可以在此處進行
回顧下上面的示例代碼 s_pserver->Start("0.0.0.0", 5555) s_pserver->Stop();
3、總結
從簡單的使用來講,3個環節
一、建立監聽器, 建立通訊組件(同時綁定監聽器)
二、填充OnXXXX等函數,好比OnReceive就打印出來,或者調用
virtual EnHandleResult OnReceive (ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) override { printf("OnReceive\n"); if(pSender->Send(dwConnID, pData, iLength)) return HR_OK; return HR_ERROR; } /***********************************/ EnHandleResult OnReceive (ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength) 中的 ITcpServer* pSender 進行 pSender->Send(dwConnID, pData, iLength) 將數據發送出去
三、主程序中,使用 CXxxPtr 智能指針進行基本的設置、啓動、關閉等動做
ps
能夠在主程序return前,執行while1,這樣程序會一直停留準備進行響應pps
1)使用g++編譯時,須要添加選項 -std=c++11
2)若是出現編譯時候一些基本類型有問題, 建議添加 #include <cstdlib>
使用HPSocket通信不須要考慮邏輯結構,直接按照方法調用就可使用了,簡單明瞭。
改變本身,從如今作起-----------久館