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服务器就搭建好了
原文链接: https://www.cnblogs.com/tian11shiyi/p/12461201.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/334754
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!