HPSocket -- 文档和下载地址 :https://www.oschina.net/p/hp-socket
HPSocket -- Github :https://github.com/ldcsaa/HP-Socket
源码文档案例可在交流群下载:QQ-75375912
* 本篇讲解的是TcpServer的使用 *
环境Ubuntu 18.04.3 编辑工具IDE QT5.13.2
在群里可以下载相关源码目录如下
我们需要的是Linux目录下的东西 将里面的东西都复制到Linux系统内
鉴于我们是简单利用TCP 开发Server 我们只需要
include,lib不过良心的作者为我们做了个install.sh和compile.sh
安装如下:
include和lib会安装在 /usr/local/include 和 /usr/local/lib64 两个目录下
打开Qt Creator 新建一个项目 Qt Widgets Application 命名为HpSocketDemo
更改Pro文件如下:
新建类MyTcpListener 包含头文件hpsocket/HPSocket.h 继承CTcpServerListener
将MyTcpListener变成单例类,再加上自己实现的事件回调类ISocketView 代码如下:
#ifndef ISOCKETVIEW_H #define ISOCKETVIEW_H //此处仅当教程使用 具体回传参数由各位根据需求来定 class ISocketView { public: virtual void onPrepareListen()=0; virtual void onAccept()=0; virtual void onHandShake() = 0; virtual void onReceive()=0; virtual void onSend()=0; virtual void onShutdown()=0; virtual void onClose()=0; }; #endif // ISOCKETVIEW_H
Server执行顺序如下:
执行startServer() 导致 OnPrepareListen触发 可进行发送数据的行为
外部Client接入连接 导致onAccept触发 可进行接受数据的行为
外部Client发送数据 导致onReceive触发
外部Client断开连接导致onClose触发
执行stopServer() 导致onClose onShutdown 触发
#ifndef MYTCPLISTENER_H #define MYTCPLISTENER_H #include "hpsocket/HPSocket.h" #include "ISocketView.h" #include <QMutex> #include <QMutexLocker> //这个类的需求请自行添加 class MySocketBuffer { public: static MySocketBuffer* newBuffer(){ return new MySocketBuffer();} MySocketBuffer(){} }; class MyTcpListener:CTcpServerListener { public: static MyTcpListener* getInstance(); CTcpPackServerPtr mServer; //1.开启服务器 bool startServer(); //2.关闭服务器 bool stopServer(); void registerView(ISocketView* view); void unRegisterView(); public: //监听成功时触发 EnHandleResult OnPrepareListen(ITcpServer *pSender, SOCKET soListen); //接受到连接时触发 EnHandleResult OnAccept(ITcpServer *pSender, CONNID dwConnID, UINT_PTR soClient); //握手成功时触发 EnHandleResult OnHandShake(ITcpServer *pSender, CONNID dwConnID); //收到数据时触发 EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength); //发送数据成功触发 EnHandleResult OnSend(ITcpServer *pSender, CONNID dwConnID, const BYTE *pData, int iLength); //服务器关闭时触发 EnHandleResult OnShutdown(ITcpServer *pSender); //关闭某个连接时触发 EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode); private: ISocketView *mView; private: //单例实现 MyTcpListener(); MyTcpListener(const MyTcpListener&); MyTcpListener& operator=(const MyTcpListener&); virtual ~MyTcpListener(); class CGarbo // { public: CGarbo(){} ~CGarbo() { if (MyTcpListener::mServerListener) { delete MyTcpListener::mServerListener; } } }; static CGarbo mCGarbo; private: static MyTcpListener* mServerListener; static QMutex mMutex; }; #endif // MYTCPLISTENER_H
#include "MyTcpListener.h" MyTcpListener* MyTcpListener::mServerListener=nullptr; QMutex MyTcpListener::mMutex; MyTcpListener::MyTcpListener() :mServer(this)//要想监听生效 这个必须传入监听者对象 ,mView(nullptr) { } MyTcpListener::~MyTcpListener() { } MyTcpListener *MyTcpListener::getInstance() { MyTcpListener* tmp = mServerListener; if (tmp == nullptr) { QMutexLocker locker(&mMutex); tmp = mServerListener; if (tmp == nullptr) { tmp = new MyTcpListener(); mServerListener = tmp; } } return mServerListener; } bool MyTcpListener::startServer() { //mServer ->SetSocketBufferSize(2048); return mServer->Start("0,0,0,0",12000); } bool MyTcpListener::stopServer() { return mServer->Stop(); } void MyTcpListener::registerView(ISocketView *view) { mView = view; } void MyTcpListener::unRegisterView() { mView=nullptr; } EnHandleResult MyTcpListener::OnPrepareListen(ITcpServer *pSender, SOCKET soListen) { //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onPrepareListen(); } //获取监听的ip port信息 TCHAR lpszAddress[30]; int iAddressLen; USHORT unPort; pSender->GetListenAddress(lpszAddress,iAddressLen,unPort); return HR_OK; } EnHandleResult MyTcpListener::OnAccept(ITcpServer *pSender, CONNID dwConnID, UINT_PTR soClient) { //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onAccept(); } //为每一个新接入的连接 附加一个对象 因为我们是根据ID来区分连接的 pSender->SetConnectionExtra(dwConnID,MySocketBuffer::newBuffer()); return HR_OK; } EnHandleResult MyTcpListener::OnHandShake(ITcpServer *pSender, CONNID dwConnID) { //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onHandShake(); } return HR_OK; } EnHandleResult MyTcpListener::OnReceive(ITcpServer *pSender, CONNID dwConnID, const BYTE *pData, int iLength) { //特别注意这个回调触发的方式 当同一个ID触发时是按照顺序触发 //如果是不同ID触发则是线程触发 所以在这里不能做阻塞处理 //特别是不能加锁做同步处理 //如果想高速处理数据 请采用线程池方式 //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onReceive(); } //这里就可以采用Accept时附加的对象做处理,比如定义方法 数据缓存等 MySocketBuffer * pSocketBuffer=nullptr; pSender->GetConnectionExtra(dwConnID,(PVOID*)pSocketBuffer); if(pSocketBuffer!=nullptr) { //可在此对pSocketBuffer做操作 } return HR_OK; } EnHandleResult MyTcpListener::OnSend(ITcpServer *pSender, CONNID dwConnID, const BYTE *pData, int iLength) { //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onSend(); } return HR_OK; } EnHandleResult MyTcpListener::OnShutdown(ITcpServer *pSender) { //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onShutdown(); } return HR_OK; } EnHandleResult MyTcpListener::OnClose(ITcpServer *pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode) { //回调触发 注意不能直接改UI Qt建议采用信号槽 if(mView!=nullptr) { mView->onClose(); } //当一个连接关闭时 我们需要自己将onAccept 时 new出来的对象delete掉 MySocketBuffer * pSocketBuffer=nullptr; pSender->GetConnectionExtra(dwConnID,(PVOID*)pSocketBuffer); if(pSocketBuffer!=nullptr){ delete pSocketBuffer;} return HR_OK; }
一个简单的TCP服务器就搭建好了