承接上章: Qt一步步搭建TcpServer3——关闭与启动
在上一章讲完Server端的安全启动与关闭之后,我整理了下代码,突然发现内容分配的不太合理,所以这章要说的东西多一点:
封装ClientManager->抽成NetApi静态库项目->在别的项目中使用该NetApi库。
1、创建ClientManager:
ClientManager其实也是类似于Server,自己维护一个会话线程池,客户端要用Session则负责创建一个Session。上层拿到Session之后,再自行封装或者使用,这样做的好处是客户端可以连接多个端,也更方便上层设计:
头文件:
#ifndef CLIENTMANAGER_H
#define CLIENTMANAGER_H
#include "SessionThreads.h"
//客户端Manager
class ClientManager
{
public:
ClientManager() = default;
~ClientManager();
//启动,默认启动一个线程,非线程安全
bool Start(uint32_t threadNum = 1);
//关闭 非线程安全
void Stop();
//获取会话数
std::vector<uint32_t> GetSessionSize() const;
//创建一个客户端
std::shared_ptr<TcpSession> CreateClient();
private:
//线程会话池
SessionThreads SessionThreads_;
//是否正在运行
bool IsRunning_ = false;
};
#endif // CLIENTMANAGER_H
从头文件就能看出来,和Server相比较,还是一样的配方,熟悉的味道。唯一的区别是,Client是负责创建Client的,上层需要一个未连接的Client去连接服务端。而Server需要启动一个监听线程。
cpp:
#include "ClientManager.h"
ClientManager::~ClientManager()
{
}
bool ClientManager::Start(uint32_t threadNum)
{
if (IsRunning_)
return false;
// 验证
if (threadNum == 0)
threadNum = std::thread::hardware_concurrency();
// 启动
this->SessionThreads_.Start(threadNum);
IsRunning_ = true;
return true;
}
void ClientManager::Stop()
{
if (!IsRunning_)
return;
// 停止会话线程池
this->SessionThreads_.Stop();
IsRunning_ = false;
}
std::vector<uint32_t> ClientManager::GetSessionSize() const
{
return this->SessionThreads_.GetSessionSize();
}
std::shared_ptr<TcpSession> ClientManager::CreateClient()
{
TcpThread *thread = this->SessionThreads_.PickMinThread();
std::shared_ptr<TcpSession> session = std::make_shared<TcpSession>(thread);
this->SessionThreads_.AddSession(session);
session->moveToThread(thread);
if(thread)
thread->AddOne();
return session;
}
这里的代码比较简单,需要简单说明下的是,我将TcpSession和TcpThread等重新整理调整了下。但是整体不影响,所以就直接在最后的代码附件里体现好了,没必要再单独拎出来,都是小改动。
2、封装成静态库:
2.1、 新建NetApi的静态库项目:
并且把之前写的那些文件添加到该项目中(如图)。
2.2、命名空间:
既然都封装成lib库了,那不妨再为我们的NetApi取个命名空间吧,这样用起来也更方便,更模块化。
在NetApi项目中新建头文件:
NetApiNameSpace.h:
#ifndef NETAPINAMESPACE_H
#define NETAPINAMESPACE_H
//命名空间
#ifndef NETAPI_NAMESPACE_BEGIN
#define NETAPI_NAMESPACE_BEGIN namespace NetAPI {
#define NETAPI_NAMESPACE_END }
#endif
#endif // NETAPINAMESPACE_H
这里用的是两个宏定义,这样在类中可以直接用宏就行了。
比如:
TcpThread:
#ifndef TCPTHREAD_H
#define TCPTHREAD_H