HPSocket介绍与使用
一、HPSocket介绍
HP-Socket是一套通用的高性能TCP/UDP/HTTP 通信框架,包含服务端组件、客户端组件和Agent组件,广泛适用于各种不同应用场景的TCP/UDP/HTTP通信系统,提供C/C++、C#、Delphi、E(易语言)、Java、Python等编程语言接口。HP-Socket对通信层完全封装,应用程序不必关注通信层的任何细节;HP-Socket提供基于事件通知模型的API接口,能非常简单高效地整合到新旧应用程序中。
1.编译
下载Hp-socket库:
git clone https://github.com/ldcsaa/HP-Socket.git
这个库有多个系统的版本,我们这里选用linux分析就好了。所以进入到Linux下,看readme大概知道编译流程。
./compile.sh
sudo ./install.sh
大概就是分两个脚本,一个编译脚本和一个安装脚本。-h参数可以分别看到他们的使用说明。
compile.sh脚本
$ ./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函数
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.
所以就是不能调用了哦。
然后这里有几种解决方法:
- 链接到.a可以解决,因为.a是把.o打包
- 不要链接.so直接链接.o
- 修改代码,换一种获取类的方式
二、使用
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 三种接收模型
1、PUSH 模型:组件接收到数据时会触发监听器对象的 OnReceive(pSender, dwConnID,pData, iLength) 事件,把数据“推”给应用程序。
2、 PULL 模型: 组件接收到数据时会触发监听器对象的 OnReceive(pSender, dwConnID,iTotalLength) 事件,告诉应用程序当前已经接收到多少数据,应用程序检查数据的长度,如果满足需要则调用组件的 Fetch(dwConnID, pData, iDataLength) 方法把需要的数据“拉”出来。
3、 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个环节
1、创建监听器, 创建通信组件(同时绑定监听器)
2、填充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) 将数据发送出去
3、主程序中,使用 CXxxPtr 智能指针进行基本的设置、启动、关闭等动作
ps
可以在主程序return前,执行while1,这样程序会一直停留准备进行响应pps
1)使用g++编译时,需要添加选项 -std=c++11
2)如果出现编译时候一些基本类型有问题, 建议添加 #include <cstdlib>
使用HPSocket通讯不需要考虑逻辑结构,直接按照方法调用就可以使用了,简单明了。
改变自己,从现在做起-----------久馆
HPSocket介绍与使用的更多相关文章
- 高性能网络通信框架 HP-Socket
HP-Socket 详细介绍 HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和Agent组件,广泛适用于各种不同应用场景的 TCP/UDP/ ...
- C++中简单使用HP-Socket
目录 简介 使用方式 实现简单线程池 实现TCP客户端 实现TCP服务端 实现Http客户端 附件 简介 HP-Socket 是一套通用的高性能 TCP/UDP /HTTP 通信 框架 ,包含服务端组 ...
- CSS3 background-image背景图片相关介绍
这里将会介绍如何通过background-image设置背景图片,以及背景图片的平铺.拉伸.偏移.设置大小等操作. 1. 背景图片样式分类 CSS中设置元素背景图片及其背景图片样式的属性主要以下几个: ...
- MySQL高级知识- MySQL的架构介绍
[TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而 ...
- Windows Server 2012 NIC Teaming介绍及注意事项
Windows Server 2012 NIC Teaming介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Windows Ser ...
- Linux下服务器端开发流程及相关工具介绍(C++)
去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把自己接触到的这些东西记录下来,为后来者提供参考,相当于一个路 ...
- JavaScript var关键字、变量的状态、异常处理、命名规范等介绍
本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...
- HTML DOM 介绍
本篇主要介绍DOM内容.DOM 节点.节点属性以及获取HTML元素的方法. 目录 1. 介绍 DOM:介绍DOM,以及对DOM分类和功能的说明. 2. DOM 节点:介绍DOM节点分类和节点层次. 3 ...
- HTML 事件(一) 事件的介绍
本篇主要介绍HTML中的事件知识:事件相关术语.DOM事件规范.事件对象. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三 ...
随机推荐
- K8S的Kafka监控(Prometheus+Grafana)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 微信小程序——【百景游戏小攻略】
微信小程序--[百景游戏小攻略] 本次课程小项目中的图片以及文章还未获得授权!请勿商用!未经授权,请勿转载! 博客班级 https://edu.cnblogs.com/campus/zjcsxy/SE ...
- 小白自己对while循环的理解
- Es6-Promise初识
Promise 含义: Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Pro ...
- 安利下PyAUtoGUI这个库,可自动化控制鼠标键盘
PyAutoGUI 不知道你有没有用过,它是一款用Python自动化控制键盘.鼠标的库.但凡是你不想手动重复操作的工作都可以用这个库来解决. 比如,我想半夜时候定时给发个微信,或者每天自动刷页面等操作 ...
- tp3.2自动验证
<?php namespace Home\Model; use Think\Model; class UserModel extends Model{ protected $patchValid ...
- 钉钉自定义机器人webhook
这篇博文主要讲的是如何进行自定义定时发送一些text类的消息的自定义机器人.添加过程不细讲了. 首先我们需要拿到一个Hook地址,就是你在添加自定义机器人的时候有个,如图: 然后开始编写我们的脚本,我 ...
- simple-rpc
RPC的实现原理 正如上一讲所说,RPC主要是为了解决的两个问题: 解决分布式系统中,服务之间的调用问题. 远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑. 还是以计算器Calc ...
- JLC PCB 嘉立创自动确认生产稿,不讲武德?耗子尾汁!!!
首先,开局一张图,嘉立创又不做人的一天.嘉立创不讲武德,耗子尾汁!!! 之前下单,勾选了确定生产稿和不加客编,结果生产稿出来还是给我加了客编.那我出10元的意思何在?让我自己花3元看我花的10元有没有 ...
- ubuntu16.04搭建LAMP(独立安装)
修改APT源 备份原文件source.list sudo cp /etc/source.list /etc/source.list.bak 修改source.list sudo vi /etc/sou ...