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通信不须要考虑逻辑结构,直接按照方法调用就可使用了,简单明了。
改变本身,从如今作起-----------久馆