当前位置: 首页 > news >正文

QT聊天项目DAY10

1.封装redis操作类

头文件

#ifndef REDISMANAGE_H
#define REDISMANAGE_H#include "Singletion.h"
#include "GlobalHead.h"class RedisManage : public Singletion<RedisManage>
{friend class Singletion<RedisManage>;
public:~RedisManage();bool Connect(const string& host, int port);											// 连接redisbool Get(const string& key, string& value);											// 获取valuebool Set(const string& key, const string& value);									// 设置valuebool Auth(const string& password);													// 验证密码bool LPush(const string& key, const string& value);									// 左侧pushbool LPop(const string& key, string& value);										// 左侧popbool RPush(const string& key, const string& value);									// 右侧pushbool RPop(const string& key, string& value);										// 右侧popbool Del(const string& key);														// 删除keybool ExitsKey(const string& key);													// 判断key是否存在void Close();																		// 关闭连接/* 将名为key的hash表中的field设置为Value */bool HSet(const string& key, const string& field, const string& value);				bool HSet(const char* key, const char* field, const char* value, size_t valuelen);/* 获取名为key的hash表中field对应的value */string HGet(const string& key, const string& field);					private:RedisManage();private:redisContext* _connect;																// redis连接redisReply* _reply;																	// redis响应对象
};
#endif // REDISMANAGE_H

实现文件

#include "RedisManage.h"RedisManage::~RedisManage()
{}RedisManage::RedisManage()
{}/* 连接redis */
bool RedisManage::Connect(const string& host, int port)
{_connect = redisConnect(host.c_str(), port);if (_connect == NULL || _connect->err){cout << "connect error " << _connect->errstr << endl;return false;}return true;
}/* 获取value */
bool RedisManage::Get(const string& key, string& value)
{_reply = (redisReply*)redisCommand(_connect, "GET %s", key.c_str());if (_reply == NULL){cout << "[ GET " << key << " ] error" << endl;freeReplyObject(_reply);return false;}/* 不是字符串 */if (_reply->type != REDIS_REPLY_STRING){cout << "[ GET " << key << " ] not string" << endl;freeReplyObject(_reply);return false;}value = _reply->str;freeReplyObject(_reply);cout << "[ GET " << key << " ] success" << endl;return true;
}/* 设置value */
bool RedisManage::Set(const string& key, const string& value)
{_reply = (redisReply*)redisCommand(_connect, "SET %s %s", key.c_str(), value.c_str());if (_reply == NULL){cout << "Execute command [ SET " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}// 执行失败则释放连接if ((_reply->type != REDIS_REPLY_STATUS && _reply->str != "ok") || _reply->str != "ok"){cout << "Execute command [ SET " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ SET " << key << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 验证密码 */
bool RedisManage::Auth(const string& password)
{_reply = (redisReply*)redisCommand(_connect, "AUTH %s", password.c_str());if (_reply->type == REDIS_REPLY_ERROR){cout << "Auth failed" << endl;freeReplyObject(_reply);return false;}else{cout << "Auth success" << endl;freeReplyObject(_reply);return true;}
}/* 左侧插入 */
bool RedisManage::LPush(const string& key, const string& value)
{_reply = (redisReply*)redisCommand(_connect, "LPUSH %s %s", key.c_str(), value.c_str());if (_reply == NULL){cout << "Execute command [ LPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}if (_reply->type != REDIS_REPLY_INTEGER || _reply->integer <= 0){cout << "Execute command [ LPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ LPush " << key << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 左侧弹出 */
bool RedisManage::LPop(const string& key, string& value)
{_reply = (redisReply*)redisCommand(_connect, "LPOP %s", key.c_str());if (_reply == NULL || _reply->type == REDIS_REPLY_NIL){cout << "Execute command [ LPop " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}value = _reply->str;freeReplyObject(_reply);cout << "Execute command [ LPop " << key << " ] success" << endl;return true;
}/* 右侧插入 */
bool RedisManage::RPush(const string& key, const string& value)
{_reply = (redisReply*)redisCommand(_connect, "RPUSH %s %s", key.c_str(), value.c_str());if (_reply == NULL){cout << "Execute command [ RPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}if (_reply->type != REDIS_REPLY_INTEGER || _reply->integer <= 0){cout << "Execute command [ RPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ RPush " << key << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 右侧弹出 */
bool RedisManage::RPop(const string& key, string& value)
{_reply = (redisReply*)redisCommand(_connect, "RPOP %s", key.c_str());if (_reply == NULL || _reply->type == REDIS_REPLY_NIL){cout << "Execute command [ RPop " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}value = _reply->str;freeReplyObject(_reply);cout << "Execute command [ RPop " << key << " ] success" << endl;return true;
}/* 将名为key的hash表中的field设置为Value */
bool RedisManage::HSet(const string& key, const string& field, const string& value)
{/* 负责传输命令 */_reply = (redisReply*)redisCommand(_connect, "HSET %s %s %s", key.c_str(), field.c_str(), value.c_str());if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER){cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}bool RedisManage::HSet(const char* key, const char* field, const char* value, size_t valuelen)
{const char* argv[4];size_t argvlen[4];argv[0] = "HSET";argvlen[0] = 4;argv[1] = key;argvlen[1] = strlen(key);argv[2] = field;argvlen[2] = strlen(field);argv[3] = value;argvlen[3] = valuelen;/* 负责传输二进制,比如图片之类的*/_reply = (redisReply*)redisCommandArgv(_connect, 4, argv, argvlen);if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER){cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 获取名为key的hash表中field对应的value */
string RedisManage::HGet(const string& key, const string& field)
{const char* argv[3];size_t argvlen[3];argv[0] = "HGET";argvlen[0] = 4;argv[1] = key.c_str();argvlen[1] = key.length();argv[2] = field.c_str();argvlen[2] = field.length();_reply = (redisReply*)redisCommandArgv(_connect, 3, argv, argvlen);if (_reply == NULL || _reply->type == REDIS_REPLY_NIL){cout << "Execute command [ HGet " << key << " " << field << " ] failed" << endl;freeReplyObject(_reply);return "";}string value = _reply->str;freeReplyObject(_reply);cout << "Execute command [ HGet " << key << " " << field << " ] success" << endl;return value;
}/* 删除key */
bool RedisManage::Del(const string& key)
{_reply = (redisReply*)redisCommand(_connect, "DEL %s", key.c_str());if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER){cout << "Execute command [ DEL " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ DEL " << key << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 判断key是否存在 */
bool RedisManage::ExitsKey(const string& key)
{_reply = (redisReply*)redisCommand(_connect, "EXISTS %s", key.c_str());if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER || _reply->integer == 0){cout << "Execute command [ ExitsKey " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ ExitsKey " << key << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 关闭连接 */
void RedisManage::Close()
{redisFree(_connect);
}

1.2 编译测试

测试一下代码

void TestRedisManage() {assert(RedisManage::GetInstance()->Connect("127.0.0.1", 6380));assert(RedisManage::GetInstance()->Auth("123456"));assert(RedisManage::GetInstance()->Set("blogwebsite", "llfc.club"));std::string value = "";assert(RedisManage::GetInstance()->Get("blogwebsite", value));assert(RedisManage::GetInstance()->Get("nonekey", value) == false);assert(RedisManage::GetInstance()->HSet("bloginfo", "blogwebsite", "llfc.club"));assert(RedisManage::GetInstance()->HGet("bloginfo", "blogwebsite") != "");assert(RedisManage::GetInstance()->ExitsKey("bloginfo"));assert(RedisManage::GetInstance()->Del("bloginfo"));assert(RedisManage::GetInstance()->Del("bloginfo"));assert(RedisManage::GetInstance()->ExitsKey("bloginfo") == false);assert(RedisManage::GetInstance()->LPush("lpushkey1", "lpushvalue1"));assert(RedisManage::GetInstance()->LPush("lpushkey1", "lpushvalue2"));assert(RedisManage::GetInstance()->LPush("lpushkey1", "lpushvalue3"));assert(RedisManage::GetInstance()->RPop("lpushkey1", value));assert(RedisManage::GetInstance()->RPop("lpushkey1", value));assert(RedisManage::GetInstance()->LPop("lpushkey1", value));assert(RedisManage::GetInstance()->LPop("lpushkey2", value) == false);RedisManage::GetInstance()->Close();
}

执行失败

set指令出问题了

指令是执行成功了的

对于char只能使用strcmp的方式去比较

2. Redis连接池

之前写了事件循环池和GRPC连接池,事件循环池中是专门处理客户端和服务器之间的通讯的,如果客户端发来数据需要存储起来的话,服务器就需要调用我们刚刚封装的RedisManage获取它的单例然后去向redis数据库中写东西,这时候就带来一个问题,如果两个线程同时写,就会产生资源竞争而如果使用互斥锁,多线程的优势又没有完全展现出来,所用封装多个redis连接的池性组件,这样就能够充分发挥多线程的优势了

从原本的一个连接,变成多个连接

池性组件中的核心function就是获取连接和还回连接

/* Redis 连接池 */
class RedisPool
{
public:RedisPool(size_t PoolSize, const char* host, int port, const char* password = "123456"): _PoolSize(PoolSize), _host(host), _port(port), bIsStop(false){for (size_t i = 0; i < PoolSize; i++){redisContext* redis = redisConnect(_host, _port);if (redis == NULL || redis->err != 0){if (redis){redisFree(redis);}continue;}redisReply* ret = (redisReply*)redisCommand(redis, "AUTH %s", password);if (ret->type == REDIS_REPLY_ERROR){cout << "Redis Auth Error: " << ret->str << endl;freeReplyObject(ret);redisFree(redis);continue;}freeReplyObject(ret);cout << "Redis Connect Success!" << endl;_pool.push(redis);}}~RedisPool(){lock_guard<mutex> lock(_mutex);bIsStop = true;_cond.notify_all();															// 唤醒所有线程while (!_pool.empty()){redisContext* redis = _pool.front();_pool.pop();redisFree(redis);}}/* 获取一个redis 连接 */redisContext* GetConnect(){unique_lock<mutex> lock(_mutex);_cond.wait(lock, [this]() {return!_pool.empty() || !bIsStop; });redisContext* redisConnection = _pool.front();_pool.pop();return redisConnection;}/* 归还一个redis 连接 */void ReturnConnect(redisContext* redis){lock_guard<mutex> lock(_mutex);if(bIsStop)return;_pool.push(redis);_cond.notify_one();																// 唤醒沉睡的线程}private:atomic<bool> bIsStop;																// 停止标志size_t _PoolSize;																	// 连接池大小const char* _host;																	// redis主机地址int _port;																			// redis端口/* 队列, 锁, 条件变量 */queue<redisContext*> _pool;															// 连接池mutex _mutex;																		// 互斥锁condition_variable _cond;															// 条件变量
};

重新修改的redis连接类

头文件

class RedisManage : public Singletion<RedisManage>
{friend class Singletion<RedisManage>;
public:~RedisManage();bool Get(const string& key, string& value);											// 获取valuebool Set(const string& key, const string& value);									// 设置valuebool Auth(const string& password);													// 验证密码bool LPush(const string& key, const string& value);									// 左侧pushbool LPop(const string& key, string& value);										// 左侧popbool RPush(const string& key, const string& value);									// 右侧pushbool RPop(const string& key, string& value);										// 右侧popbool Del(const string& key);														// 删除keybool ExitsKey(const string& key);													// 判断key是否存在void Close();																		// 关闭连接/* 将名为key的hash表中的field设置为Value */bool HSet(const string& key, const string& field, const string& value);				bool HSet(const char* key, const char* field, const char* value, size_t valuelen);/* 获取名为key的hash表中field对应的value */string HGet(const string& key, const string& field);					private:RedisManage();private:RedisPool* _redisPool;																// redis连接池redisReply* _reply;																	// redis响应对象
};
#endif // REDISMANAGE_H

实现文件

#include "RedisManage.h"
#include "ServerStatic.h"RedisManage::~RedisManage()
{}RedisManage::RedisManage()
{const char* ip = get<string>(ServerStatic::ParseConfig("Redis", "Host")).c_str();int Port = get<int>(ServerStatic::ParseConfig("Redis", "Port"));_redisPool = new RedisPool(5,ip, Port);
}/* 获取value */
bool RedisManage::Get(const string& key, string& value)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "GET %s", key.c_str());if (_reply == NULL){cout << "[ GET " << key << " ] error" << endl;freeReplyObject(_reply);return false;}/* 不是字符串 */if (_reply->type != REDIS_REPLY_STRING){cout << "[ GET " << key << " ] not string" << endl;freeReplyObject(_reply);return false;}value = _reply->str;freeReplyObject(_reply);cout << "[ GET " << key << " ] success" << endl;return true;
}/* 设置value */
bool RedisManage::Set(const string& key, const string& value)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "SET %s %s", key.c_str(), value.c_str());if (_reply == NULL){cout << "Execute command [ SET " << key << " " << value << " ] failed   _reply == NULL" << endl;freeReplyObject(_reply);return false;}// 执行失败则释放连接if ((_reply->type != REDIS_REPLY_STATUS && strcmp(_reply->str, "OK") != 0) || strcmp(_reply->str, "OK") != 0){cout << "Execute command [ SET " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ SET " << key << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 验证密码 */
bool RedisManage::Auth(const string& password)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "AUTH %s", password.c_str());if (_reply->type == REDIS_REPLY_ERROR){cout << "Auth failed" << endl;freeReplyObject(_reply);return false;}else{cout << "Auth success" << endl;freeReplyObject(_reply);return true;}
}/* 左侧插入 */
bool RedisManage::LPush(const string& key, const string& value)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "LPUSH %s %s", key.c_str(), value.c_str());if (_reply == NULL){cout << "Execute command [ LPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}if (_reply->type != REDIS_REPLY_INTEGER || _reply->integer <= 0){cout << "Execute command [ LPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ LPush " << key << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 左侧弹出 */
bool RedisManage::LPop(const string& key, string& value)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "LPOP %s", key.c_str());if (_reply == NULL || _reply->type == REDIS_REPLY_NIL){cout << "Execute command [ LPop " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}value = _reply->str;freeReplyObject(_reply);cout << "Execute command [ LPop " << key << " ] success" << endl;return true;
}/* 右侧插入 */
bool RedisManage::RPush(const string& key, const string& value)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "RPUSH %s %s", key.c_str(), value.c_str());if (_reply == NULL){cout << "Execute command [ RPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}if (_reply->type != REDIS_REPLY_INTEGER || _reply->integer <= 0){cout << "Execute command [ RPush " << key << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ RPush " << key << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 右侧弹出 */
bool RedisManage::RPop(const string& key, string& value)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "RPOP %s", key.c_str());if (_reply == NULL || _reply->type == REDIS_REPLY_NIL){cout << "Execute command [ RPop " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}value = _reply->str;freeReplyObject(_reply);cout << "Execute command [ RPop " << key << " ] success" << endl;return true;
}/* 将名为key的hash表中的field设置为Value */
bool RedisManage::HSet(const string& key, const string& field, const string& value)
{/* 负责传输命令 */_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "HSET %s %s %s", key.c_str(), field.c_str(), value.c_str());if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER){cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}bool RedisManage::HSet(const char* key, const char* field, const char* value, size_t valuelen)
{const char* argv[4];size_t argvlen[4];argv[0] = "HSET";argvlen[0] = 4;argv[1] = key;argvlen[1] = strlen(key);argv[2] = field;argvlen[2] = strlen(field);argv[3] = value;argvlen[3] = valuelen;/* 负责传输二进制,比如图片之类的*/_reply = (redisReply*)redisCommandArgv(_redisPool->GetConnect(), 4, argv, argvlen);if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER){cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ HSet " << key << " " << field << " " << value << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 获取名为key的hash表中field对应的value */
string RedisManage::HGet(const string& key, const string& field)
{const char* argv[3];size_t argvlen[3];argv[0] = "HGET";argvlen[0] = 4;argv[1] = key.c_str();argvlen[1] = key.length();argv[2] = field.c_str();argvlen[2] = field.length();_reply = (redisReply*)redisCommandArgv(_redisPool->GetConnect(), 3, argv, argvlen);if (_reply == NULL || _reply->type == REDIS_REPLY_NIL){cout << "Execute command [ HGet " << key << " " << field << " ] failed" << endl;freeReplyObject(_reply);return "";}string value = _reply->str;freeReplyObject(_reply);cout << "Execute command [ HGet " << key << " " << field << " ] success" << endl;return value;
}/* 删除key */
bool RedisManage::Del(const string& key)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "DEL %s", key.c_str());if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER){cout << "Execute command [ DEL " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ DEL " << key << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 判断key是否存在 */
bool RedisManage::ExitsKey(const string& key)
{_reply = (redisReply*)redisCommand(_redisPool->GetConnect(), "EXISTS %s", key.c_str());if (_reply == NULL || _reply->type != REDIS_REPLY_INTEGER || _reply->integer == 0){cout << "Execute command [ ExitsKey " << key << " ] failed" << endl;freeReplyObject(_reply);return false;}cout << "Execute command [ ExitsKey " << key << " ] success" << endl;freeReplyObject(_reply);return true;
}/* 关闭连接 */
void RedisManage::Close()
{redisFree(_redisPool->GetConnect());
}

重新修改读取配置文件类,采用c++17的variant来返回

static variant<int, string> ParseConfig(string blockName, string key, string configPath = "./Config/config.json");/* 解析配置文件 */
variant<int, string>ServerStatic::ParseConfig(string blockName, string key, string configPath)
{ifstream file(configPath, ifstream::binary);if (!file.is_open()){cerr << "Failed to open config file: " << configPath << endl;return {};}Json::Value jsonResult;Json::Reader reader;if (!reader.parse(file, jsonResult)){cout << "Failed to parse config file: " << configPath << endl;return {};}if (!jsonResult.isMember(blockName)){cout << "Failed to find block: " << blockName << endl;return {};}const Json::Value& value = jsonResult[blockName][key];if (value.isInt()){return value.asInt();}else if (value.isString()){return value.asString();}return {};
}

2.2 编译测试

报错,说std::iterator什么什么的

C++17 中,标准库弃用了std::iterator,可以定义_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING来屏蔽这个错误

编译成功

redis连接池编写成功

相关文章:

  • 【Golang】gin框架动态更新路由
  • WebRTC流媒体传输协议RTP点到点传输协议介绍,WebRTC为什么使用RTP协议传输音视频流?
  • 电压取样端口静电浪涌防护方案 之6TS Series瞬态抑制器TVS
  • 2025年社交APP安全防御指南:抵御DDoS与CC攻击的实战策略
  • 【免杀】C2免杀 | 概念篇
  • Python 爬虫基础入门教程(超详细)
  • 2025数字孪生技术全景洞察:从工业革命到智慧城市的跨越式发展
  • 进入虚拟机单用户模式(Linux系统故障排查)
  • Vscode 顶部Menu(菜单)栏消失如何恢复
  • Java——反射
  • 操作系统 == 内存管理
  • FAISS 与机器学习、NLP 的关系
  • android-ndk开发(11): 安装 repo 命令
  • 一场陟遐自迩的 SwiftUI + CoreData 性能优化之旅(下)
  • YOLOv1模型架构、损失值、NMS极大值抑制
  • auto推导类型原则
  • 2025数维杯数学建模竞赛B题完整参考论文(共38页)(含模型、代码、数据)
  • 如何优化系统启动时间--基于米尔瑞萨MYD-YG2LX开发板
  • LeetCode百题刷001双指针·快慢指针
  • Kaggle图像分类竞赛实战总结详细代码解读
  • 解放军仪仗分队参加白俄罗斯纪念苏联伟大卫国战争胜利80周年阅兵活动
  • 巴基斯坦称回应挑衅,对印度发起军事行动
  • 央行设立服务消费与养老再贷款,额度5000亿元
  • 中方就乌克兰危机提出新倡议?外交部:中方立场没有变化
  • 江西省直机关工委副书记熊亮华履新宜春市委常委、宣传部部长
  • 山寨“小米”智能马桶、花洒销售额过亿,被判赔3500万元