前言:
本章为本人在学习QT网盘时学到的知识,在此记录。
一、QT日志
1、前因
(1)网盘服务端需要记录每一个登陆者登录的时间,账号名,在遇到除操作错误的错误时候会统计到日志中,同时客户的意见反馈也写入其中。(2)加上互斥锁防止多线程写入时混乱。
2、互斥锁
(1)定义:在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。比如说,同一个文件,可能一个线程会对其进行写操作,而另一个线程需要对这个文件进行读操作,可想而知,如果写线程还没有写结束,而此时读线程开始了,或者读线程还没有读结束而写线程开始了,那么最终的结果显然会是混乱的。为了保护共享资源,在线程里也有这么一把锁——互斥锁(mutex),互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( unlock )。
(2)try_lock():如果互斥锁是未锁定状态,得到了互斥锁所有权并加锁成功,函数返回 true 如果互斥锁是锁定状态,无法得到互斥锁所有权加锁失败,函数返回 false。而lock() 函数用于给临界区加锁,并且只能有一个线程获得锁的所有权,它有阻塞线程的作用。二者的区别在于程 try_lock() 不会阻塞线程,lock() 会阻塞线程。
3、日志实现
运用中只需要用logInfo(//想记录的文字)(或其他)即log()函数
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <string>
#include <fstream>
#include <QMessageBox>
using namespace std;
#define logDebug(format)\
Logger::getinstance().log(Logger::DEBUG,__FILE__,__LINE__,format);//__FILE__与__LINE__是表示当前所在文件,行数的宏
#define logInfo(format)\
Logger::getinstance().log(Logger::INFO,__FILE__,__LINE__,format);
#define logHelp(format)\
Logger::getinstance().log(Logger::HELP,__FILE__,__LINE__,format);
#define logWarn(format)\
Logger::getinstance().log(Logger::WARN,__FILE__,__LINE__,format);
#define logError(format)\
Logger::getinstance().log(Logger::ERROR,__FILE__,__LINE__,format);
class Logger
{
public:
enum Level
{
DEBUG = 0,
INFO,
HELP,
WARN,
ERROR,
LEVEL_COUNT
};
static Logger& getinstance();
void open(const string& filename);
void foutClose();
void log(Level level, const char* file, int line, const char* format);
void level(Level level)
{
m_level = level;
}
void setMax(int bytes)
{
m_max = bytes;
}
Logger();
~Logger();
private:
void rotate();
string m_filename;
ofstream m_fout;//输入流
static const char* s_level[LEVEL_COUNT];
Level m_level;
int m_max;
int m_len;
};
#endif // LOGGER_H
logger.cpp
#include "logger.h"
#include <time.h>
#include <string.h>
#include <iostream>
#include <mutex>
using namespace std;
mutex log_mutex;
const char* Logger::s_level[LEVEL_COUNT] = {
"DEBUG",
"INFO",
"HELP",
"WARN",
"ERROR",
};
Logger& Logger::getinstance()
{
static Logger instance;
return instance;
}
Logger::Logger():m_level(DEBUG),m_max(0),m_len(0)
{
}
Logger::~Logger()
{
foutClose();
}
void Logger::open(const string& filename)
{
m_fout.open(filename, ios::app);
if (m_fout.fail())
{
QMessageBox::warning(NULL,"打开日志","打开日志失败");
}
m_fout.seekp(0, ios::end);
m_len = m_fout.tellp(); //获取当前已写入的大小
}
void Logger::foutClose()
{
m_fout.close();
}
void Logger::rotate()
{
foutClose();
time_t ticks = time(NULL);
struct tm* ptm = localtime(&ticks);
char timestamp[32];
memset(timestamp, 0, sizeof(timestamp));
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", ptm);
string filename = m_filename + timestamp;
if (rename(m_filename.c_str(), filename.c_str()) != 0)
{
QMessageBox::warning(NULL,"更换新日志","更换新日志失败");
}
open(m_filename);
}
void Logger::log(Level level, const char* file, int line, const char* format)
{
if (m_level > level) //信息等级不到设置等级即不记录到日志中
{
return;
}
log_mutex.lock(); //上锁保证线程安全
if (m_fout.fail())
{
QMessageBox::warning(NULL,"打开日志","打开日志失败");
}
time_t ticks= time(NULL);
struct tm* ptm = localtime(&ticks);
char timestamp[32];
memset(timestamp, 0, sizeof(timestamp));
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", ptm); //将时间戳转为字符形式的时间
const char* fmt = "%s %s %s:%d ";
int size = snprintf(NULL, 0, fmt, timestamp, s_level[level], file, line);
if (size > 0)
{
char* buffer = new char[size + 1];
snprintf(buffer, size + 1, fmt, timestamp, s_level[level], file, line); //整合信息
buffer[size] = '\0';
m_fout << buffer; //将buffer信息存入日志中
m_len += size;
delete[] buffer;
}
size = snprintf(NULL,0,format);
if (size > 0)
{
char* content = new char[size + 64]; //大小取大方便输入中文
strcpy(content,format);
m_len += size;
m_fout << content;
}
m_fout <<"\n";
m_fout.flush();//刷新缓冲,使内容写入磁盘
if (m_len >= m_max && m_max > 0)
{
rotate();
}
log_mutex.unlock();
}
二、qss
1、前因
对每个控件定制样式和制作登录界面的时候用QPaintEvent不太方便,于是用QSS进行美化。
2、qss 文件样式:
控件名前加个 #代表指定某个控件;
border - image 表示填充整个背景;
background - image 表示设置背景,但不填充;
border 表示边框大小;
border:none表示去掉边框
border - radius 表示边框圆角大小;
color 表示字体颜色; background-color表示背景颜色; background - position 表示图片位置;
background - repeat 表示图片是否重复显示;
三、加密
1、前因
将客户端输入的密码加密存储到数据库中既能防止传输过程中泄露由能防止数据库人员知晓客户密码。
2、凯撒密码
1、核心原理
其核心原理是通过将明文中的每个字母按照一定的规律进行替换,从而得到密文。这个规律通常是按照字母表顺序将每个字母移动固定的位数。
2、安全性低
(1)凯撒密码是一种非常简单的加密方式,因为总共只有 26 种可能的位移量(假设使用 26 个字母的英文字母表),其安全性较低。
(2)通过统计密文的字母频率也有可能破解密码。在大多数语言中,字母的出现频率是相对固定的(例如在英语中,字母 “e” 出现的频率最高),如果密文足够长,密码分析者可以根据这个频率特征来猜测位移量。
3、实现代码
#include <iostream>
#include <string>
using namespace std;
//加密
string encrypt(string plaintext, int key) {
string ciphertext = "";
for (char c : plaintext) {
ciphertext += char(int(c) + key);
}
return ciphertext;
}
//解密
string decrypt(string ciphertext, int key) {
string plaintext = "";
for (char c : ciphertext)
{
plaintext += char(int(c) - key);
}
return plaintext;
}
int main() {
string plaintext = "caixukun520";
int key = 5;
string encryptedtext = encrypt(plaintext, key);
cout << encryptedtext <<endl; //输出结果为: hfn}zpzs:75即为密文
string decryptedtext =decrypt(encryptedtext,key);
cout <<decryptedtext; //输出结果为caixukun520即为原来的密码
return 0;
}
3、维吉尼亚密码
1、核心原理
维吉尼亚密码是在凯撒密码的基础上扩展而来的多表密码。与简单的单表代换密码(如凯撒密码)不同,维吉尼亚密码使用多个凯撒密码进行加密,密钥的长度决定了使用多少个不同的凯撒密码。
加密时,需要使用一个密钥词,这个密钥词由字母组成,长度可以任意。密钥词会重复使用,直到与明文长度相同(因为每个明文都要对应密匙加密)。
2、安全性
相较于凯撒密码安全性高上许多,但因为维吉尼亚密码的密钥是循环重复的,通过分析密文中相同字符组之间的距离,可以推测出密钥的长度(卡西斯基试验)。一旦确定了密钥长度,密文就能重新写成多列,列数与密钥长度对应。这样每一列其实就是一个凯撒密码从而破译。
3、实现代码
#include <iostream>
#include <string>
using namespace std;
char table[95][95];
char table1[95];
//方式一
void Init1()
{
for (int i = 0; i < 95; i++)
{
table1[i] = 32 + i;//从字符空格开始,系统字符不能打印
}
}
//加密
char* encrypt1(char* plaintext, char* key, int size)
{
char* tempPlaintext = plaintext;
char* tempKey = key;
char* dest = new char[size];
char* tempDest = dest;
while (true)
{
*tempDest = table1[((*tempKey) - 32 + (*tempPlaintext) - 32) % 95];
tempDest++;
if (!(*(++tempKey)))
tempKey = key;
if (!(*(++tempPlaintext)))
break;
}
dest[size - 1] = { '\0' };//添加结束符;
return dest;
}
//方式二
void Init2()
{
for (int i = 0; i < 95; i++)
{
for (int j = 0; j < 95; j++)
{
table[i][j] =32+(i+j) %95; //从字符空格开始,系统字符不能打印
}
}
}
//加密
char* encrypt2(char* plaintext, char* key, int size) {
char* tempPlaintext = plaintext;
char* tempKey = key;
char* dest = new char[size];
char* tempdest = dest;
while (1)
{
*tempdest = table[(*tempKey) - 32][(*tempPlaintext) - 32];
tempdest++;
if (!(*(++tempKey)))
tempKey = key;
if (!(*(++tempPlaintext)))
break;
}
dest[size - 1] = { '\0' };//添加结束符;
return dest;
}
//解密
char* decrypt(char* encryptedtext, char* key, int size)
{
char* tempText = encryptedtext;
char* tempKey = key;
char* dest = new char[size];
char* tempDest=dest;
char c;
while (true)
{
c = (*tempText-32) - (*tempKey-32);
if (c < 0)
{
c = c + 95;//大于0说明没取模,直接相等,小于0则加上取掉的长度
}
*tempDest = 32 + c; //offset为在原表中的位置,应加上32
tempDest++;
if (!(*(++tempKey)))
tempKey = key;
if (!(*(++tempText)))
break;
}
dest[size - 1] = { '\0' };//添加结束符;
return dest;
return dest;
}
int main() {
Init1();
Init2();
string strPlaintext = "caixukun520";
string strKey = "hajimi";
char *caPlaintext=new char[strPlaintext.length() + 1];//方便自定义明文密码
int size = strPlaintext.length() + 1;
strcpy(caPlaintext,strPlaintext.c_str());
char *caKey = new char[strKey.length() + 1];
strcpy(caKey, strKey.c_str());
char* encryptedtext1 = encrypt1(caPlaintext, caKey, size);
char* encryptedtext2 = encrypt2(caPlaintext, caKey, size);
cout << encryptedtext1 << endl; //输出结果为: LCTbcU^P {}即为密文
cout << encryptedtext2 << endl; //输出结果一致
char* decryptedtext=decrypt(encryptedtext1, caKey, size);
cout << decryptedtext; //输出结果为:caixukun520,解密成功
return 0;
}
标签:__,char,QT,level,int,网盘,qss,Logger,size
From: https://blog.csdn.net/niairuochen/article/details/144546313