概述:
随堂笔记欢迎批评指正
1.前面文章我们分享过生成lic文件案例Qt之程序加密授权[1]并介绍了Qt自带加密算法;
2.接下来我们分享下配套的服务器实现,包括授权文件读取,授权加密字符串判断、授权时间判断、以及相关配置文件作用;
3.服务从界面上一共有两个功能:
(1).获取当前设备详细信息,并生成.txt文件;获取设备信息
(2).读取前面文章生成的.lic文件,进行逻辑处理并告诉客户端授权是否成功;生成.lic文件
示例代码:
.h:
#pragma once
#include <QObject>
#include <QtNetwork>
class APDServer : public QObject
{
Q_OBJECT
public:
APDServer(QObject *parent = nullptr);
~APDServer();
/*
* @brief:关闭服务端
*/
void closeServer();
/*
* @brief:创建配置文件
*/
bool CreateConfigFile(const QStringList &licData);
private:
/*
* @brief:初始化相关操作
*/
void initAll();
/*
* @brief:初始化网络相关
*/
void initSocket();
/*
* @brief:返回加密后字符串
*/
QString getEncryptionStr();
/*
* @brief:读取网络配置文件
*/
QStringList readConfigNetWork();
void socketEroorMessage();
private slots:
/*
* @brief: 当有新链接到来触发槽函数
*/
void slot_AcceptConnection();
/**
* @brief 当有新数据到来时调用此槽函数
*/
void slot_SocketReadData();
/*
* @brief:当有客户端连接失败或退出时触发槽函数
*/
void slot_TcpError(QAbstractSocket::SocketError);
public slots :
/*
* @brief:接收lic文件路径
*/
void slot_RecvLicFileData(const const QStringList licList);
private:
QTcpServer *tcpServer; //监听套接字
QTcpSocket *tcpSocket; //通信套接字
QStringList mlistLic; //加密后字符串
bool licFlag; //授权成功与失败标志位
};
.cpp:
#include "APDServer.h"
#include "GlobalApiClass.h"
#include <QDir>
#include <QDate>
APDServer::APDServer(QObject *parent)
: QObject(parent)
,tcpServer(nullptr)
,tcpSocket(nullptr)
,licFlag(false)
{
initAll();
}
APDServer::~APDServer()
{
if (tcpServer)
{
delete tcpServer;
tcpServer = nullptr;
}
if (tcpSocket)
{
delete tcpSocket;
tcpSocket = nullptr;
}
}
void APDServer::closeServer()
{
tcpSocket->disconnectFromHost();
tcpSocket->close();
tcpServer->close();
}
bool APDServer::CreateConfigFile(const QStringList &licData)
{
//判断路径下是否已创建文件夹没有则创建
QDir dir("C:/Desktops");
if (!dir.exists())
{
dir.mkdir("C:/Desktops");
}
dir.setFilter(QDir::Files);
QString path = "C:/Desktops/License.ini";
QSettings *config = new QSettings(path, QSettings::IniFormat);
QString date = QDate::currentDate().toString("yyyy/MM/dd");
QString time = QTime::currentTime().toString("hh:mm:ss");
//写入数据
config->setValue("/License/Start", licData.at(5));
config->setValue("/License/End", licData.at(2));
//读取数据
QString s = config->value("/License/Start").toString(); //2020/01/22-12:12:12
QString e = config->value("/License/End").toString(); //2025/01/22-12:12:12
QString c = config->value("/License/Current").toString(); //2021/01/22-17:27:38
if (c.isEmpty())
{
config->setValue("/License/Current", date + "-" + time);
c = config->value("/License/Current").toString(); //2021/01/22-17:27:38
}
delete config;
//默认授权起始时间12:12:12
//默认授权终止时间12:12:12
//授权起始时间
int s_y = s.split("/").at(0).toInt();//年
int s_m = s.split("/").at(1).toInt();//月
int s_d = s.split("/").at(2).toInt();//日
//授权终止时间
int e_y = e.split("/").at(0).toInt();
int e_m = e.split("/").at(1).toInt();
int e_d = e.split("/").at(2).toInt();
//用户登录当前时间
int f_y = c.split("-").at(0).split("/").at(0).toInt();
int f_m = c.split("-").at(0).split("/").at(1).toInt();
int f_d = c.split("-").at(0).split("/").at(2).toInt();
int f_hh = c.split("-").at(1).split(":").at(0).toInt();
int f_mm = c.split("-").at(1).split(":").at(1).toInt();
int f_ss = c.split("-").at(1).split(":").at(2).toInt();
//当前系统时间
int c_y = QDate::currentDate().toString("yyyy/MM/dd").split("/").at(0).toInt();
int c_m = QDate::currentDate().toString("yyyy/MM/dd").split("/").at(1).toInt();
int c_d = QDate::currentDate().toString("yyyy/MM/dd").split("/").at(2).toInt();
int c_hh = QDateTime::currentDateTime().toString("hh:mm:ss").split(":").at(0).toInt();
int c_mm = QDateTime::currentDateTime().toString("hh:mm:ss").split(":").at(1).toInt();
int c_ss = QDateTime::currentDateTime().toString("hh:mm:ss").split(":").at(2).toInt();
if ((c_y > s_y) && (c_y < e_y)) //当前年 > 起始年 && 当前年 < 终止年
{
if (c_y > f_y) //当前年 > 上次登录年
{
return true;
}
else if (c_y == f_y) //当前年 == 上次登录年
{
if (c_m > f_m) //当前月 > 上次登录月
{
return true;
}
else if (c_m == f_m) //当前月 == 上次登录月
{
if (c_d > f_d) //当前日 > 上次登录日
{
return true;
}
else if (c_d == f_d) //当前日 == 上次登录日
{
if (c_hh > f_hh) //当前小时 > 上次登录小时
{
return true;
}
else if (c_hh == f_hh) //当前小时 == 上次登录小时
{
if (c_mm > f_mm) //当前分钟 > 上次登录分钟
{
return true;
}
else if (c_mm == f_mm) //当前分钟 == 上次登录分钟
{
if (c_ss > f_ss) //当前秒 > 上次登录秒
{
return true;
}
else
{
return false;
}
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else if ((c_y == e_y)) //当前年 == 终止年
{
if ((c_m < e_m) && (c_m > f_m)) //当前月 < 终止月 && 当前月 > 上次登录月
{
return true;
}
else if ((c_m < e_m) && (c_m == f_m))//当前月 < 终止月 && 当前月 == 上次登录月
{
if (c_d > f_d) //当前日 > 上次登录日
{
return true;
}
else if (c_d == f_d) //当前日 ==上次登录日
{
if (c_hh > f_hh) //当前小时 > 上次登录小时
{
return true;
}
else if (c_hh == f_hh) //当前小时 == 上次登录小时
{
if (c_mm > f_mm) //当前分钟 > 上次登录分钟
{
return true;
}
else if (c_mm == f_mm) //当前分钟 == 上次登录分钟
{
if (c_ss > f_ss) //当前秒 > 上次登录秒
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else if (c_m == e_m)
{
if (c_d < e_d)
{
return true;
}
else if (c_d == e_d)
{
if (c_hh < 12)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else if ((c_y < e_y) && (c_y == s_y)) //当前时间 < 终止时间 && 当前时间 == 起始时间
{
if (c_m > f_m) //当前月 > 上次登录月
{
return true;
}
else if (c_m == f_m) //当前月 == 上次登录月
{
if (c_d > f_d) //当前日 > 上次登录日
{
return true;
}
else if (c_d == f_d) //当前日 == 上次登录日
{
if (c_hh > f_hh) //当前小时 > 上次登录小时
{
return true;
}
else if (c_hh == f_hh) //当前小时 == 上次登录小时
{
if (c_mm > f_mm) //当前分钟 > 上次登录分钟
{
return true;
}
else if (c_mm == f_mm) //当前分钟 == 上次登录分钟
{
if (c_ss > f_ss) //当前秒 > 上次登录秒
{
return true;
}
else
{
return false;
}
}
}
else
{
return false;
}
}
}
}
return false;
}
void APDServer::initAll()
{
initSocket();
}
void APDServer::initSocket()
{
QStringList list = readConfigNetWork();
if (list.isEmpty() || list.size() < 3)
return;
tcpServer = new QTcpServer(this);
if (list.at(0).compare("pc") == 0)//单机
{
if (!tcpServer->listen(QHostAddress("127.0.0.1"), list.at(2).toInt()))//监听失败
{
//输出到日志
return;
}
}
else if(list.at(0).compare("pcs") == 0)//局域网
{
QString str = GlobalApiClass::GetInstance().getAddIP();
if (!tcpServer->listen(QHostAddress(GlobalApiClass::GetInstance().getAddIP()), list.at(2).toInt()))//监听失败
{
//输出到日志
return;
}
}
connect(tcpServer, &QTcpServer::newConnection, this, &APDServer::slot_AcceptConnection);
}
QString APDServer::getEncryptionStr()
{
if (mlistLic.isEmpty())
return "error";
QString lic = GlobalApiClass::GetInstance().getUserName() +
GlobalApiClass::GetInstance().getAddIP() +
GlobalApiClass::GetInstance().getDiskdrive() +
GlobalApiClass::GetInstance().getHostMacAddress() +
GlobalApiClass::GetInstance().getCpuID() +
mlistLic.at(2) +
mlistLic.at(4) +
mlistLic.at(1) +
mlistLic.at(5);
QByteArray hashData = QCryptographicHash::hash(lic.toLocal8Bit(), QCryptographicHash::Sha3_512);
QString hex = hashData.toHex();
qDebug() << "Lic:" << hex;//输出到日志
return hex;
}
QStringList APDServer::readConfigNetWork()
{
//读取网络配置文件
QStringList list;
QSettings *config = new QSettings(QCoreApplication::applicationDirPath() + "/ConfigNetWork.ini", QSettings::IniFormat);
QString pc = config->value("/Socket/config").toString();
QString ip = config->value("/Socket/ip").toString();
QString port = config->value("/Socket/port").toString();
delete config;
list << pc << ip << port;
return list;
}
void APDServer::socketEroorMessage()
{
int len = tcpSocket->write("Error");
bool flag = tcpSocket->waitForBytesWritten(); //等待数据发送完毕
if (len > 0 && flag)
{
//输出到日志
}
}
void APDServer::slot_AcceptConnection()
{
//取出套接字
tcpSocket = tcpServer->nextPendingConnection();
//当有客户端发送数据时,触发信号
connect(tcpSocket, &QTcpSocket::readyRead, this, &APDServer::slot_SocketReadData);
//错误信息
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slot_TcpError(QAbstractSocket::SocketError)));
qDebug() << "New Connect Success" << "-----" << "Server IP:" << tcpSocket->peerAddress().toString() << "LoalPort:" << tcpSocket->localPort() << "Port:" << tcpSocket->peerPort() ;
}
void APDServer::slot_SocketReadData()
{
QByteArray buf = tcpSocket->readAll();
nNumber++;
if(mlistLic.isEmpty())
{
socketEroorMessage();
//授权标志位
licFlag = false;
}
else if (nNumber <= mlistLic.at(4).toInt())
{
if (buf.contains("RequestForAuthorization")) //客户端上线发来请求授权
{
if (mlistLic.at(6).compare(getEncryptionStr()) == 0) //加密字符串相同
{
if (CreateConfigFile(mlistLic))
{
int len = tcpSocket->write("Success");
bool flag = tcpSocket->waitForBytesWritten(); //等待数据发送完毕
if (len > 0 && flag)
{
qDebug() << "Server tcpSocket->write(Success)" << len << "PC number" << nNumber;
}
//授权标志位
licFlag = true;
}
else
{
socketEroorMessage();
//授权标志位
licFlag = false;
}
}
else
{
socketEroorMessage();
//授权标志位
licFlag = false;
}
}
else
{
socketEroorMessage();
//授权标志位
licFlag = false;
}
}
else
{
socketEroorMessage();
//授权标志位
licFlag = false;
}
}
void APDServer::slot_TcpError(QAbstractSocket::SocketError)
{
int error = tcpSocket->error();
switch (error)
{
case QAbstractSocket::RemoteHostClosedError://客户端断开-将客户端退出时间进更新
{
nNumber--;
if (nNumber < 0){
nNumber = 0;
}
qDebug() << "Client Disconnect IP:" << tcpSocket->QAbstractSocket::peerAddress().toString() << "PC number:" << nNumber;
if (licFlag)
{
//授权成功情况下,客户端退出更新我们配置文件的当前时间
QString path = "C:/Desktops/License.ini";
//读取
QSettings *config = new QSettings(path, QSettings::IniFormat);
QString date = QDate::currentDate().toString("yyyy/MM/dd");
QString time = QTime::currentTime().toString("hh:mm:ss");
config->setValue("/License/Current", date + "-" + time);
delete config;
}
//授权标志位
licFlag = false;
break;
}
default:
break;
}
}
void APDServer::slot_RecvLicFileData(const QStringList licList)
{
mlistLic = licList;
}
License.ini:
[License]
Start=2021/02/24 //授权开始时间
End=2021/03/24 //授权终止时间
Current=2021/03/16-11:30:18 //客户端每次退出时间
ConfigNetWork.ini:
[Socket]
config=pc
ip=127.0.0.1
port=6688
README="[ip is Reservation] [config = pc (Single machine)] [config = pcs (LAN)]"
说明: ConfigNetWork.ini配置文件为我们自己使用,在发布给客户使用前我们进行配置,分为单机、局域网、网络版。
运行效果图:
over:
欢迎大家关注作者在文末评论、点赞、转发以及批评指正!
如果大家有更好的方法或有问题可以在文末评论一起讨论!
共同学习!
共同进步!
文末一句话:
青年时种下什么,老年时就收获什么。