MFC项目如何使用hiredis库连接redis

news2024/11/24 17:31:33

如何在windows平台使用c++连接redis

  • 1. 下载hiredis的vs工程文件
  • 2. 使用vs2022编译hiredis
  • 3.项目中调用
  • 4. 集群连接
  • 5. 简单的封装下

最近需要在windows PC终端读取redis数据。我这里使用hiredis连接redis. 工程是vs2022开发的。

注意:如果是使用的‘hiredis’就不能在项目里面使用windows socket一类的函数了,应该‘hiredis’把这些函数全部替换了。无语!!目前我没找到简单的解决方法,除非改它源码,麻烦。

1. 下载hiredis的vs工程文件

windows平台需要自己编译hiredis这个库,这个是一个静态库,所以使用它的终端程序也要改成静态库模式。如果你的程序是用动态库的方式构架的,恭喜了,用不了, 需要自己在封装一层。

官网地址是https://github.com/redis/hiredis, 这个地址是没有vs工程的,但好心的微软提供了vs工程文件,我们直接到微软提供的地址上下载就可以https://github.com/microsoft/hiredis. 工程文件入下图
在这里插入图片描述
把整个项目都下载下来就可以。

2. 使用vs2022编译hiredis

启动vs的工程项目,工程名称见下图
在这里插入图片描述
工程就可以打开了
在这里插入图片描述
然后编译,hiredis和Win32_Interop这个两个项目就可以。
在编译Win32_Interop时可能会有报错编译不过买这个时候最简单就是将错误的地方注释掉,这边这些倒错都是报异常的代码,可以不用管。
把编译出来的lib放到一个lib目录里面
然后需要把头文件也考出来
deps\hiredies\hiredies.h
src\Win32_Interop\win32_types_hiredis.h
修改一下 hiredies.h 文件中引用 win32_types_hiredis.h 的代码:因为路径变了,将原来的注释掉
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.项目中调用

在项目中引入工厂的include目录和lib目录, 然后添加hiredis.lib,Win32_Interop.lib到以来依赖库中
在这里插入图片描述
在这里插入图片描述
然后把项目改成静态库模式
在这里插入图片描述
在这里插入图片描述
我的是MFC项目,所有MFC也要改成静态库模式
在这里插入图片描述

这样就大功告成了!!!!!!

4. 集群连接

有第3方库支持主备集群切换,但是还要自己下载编译,太太麻烦了, 直接看了原理,也就是配置多个服务器地址,连接一个服务器以后,查询下服务器的状态,是不是主的就主的就用这个连接,否在查询一个服务器地址。重连也是一样。使用命令”info replication“可以查询服务器的状态,找”role:master“这个字符串就可以了。

5. 简单的封装下

由于redisReply每次返回数据都要手动删除,直接封一个智能指针。这样就不用自己手动释放了, 我的项目都是unicode。

class AutoRedisReply
{
public:
	redisReply* m_pRedisReply = NULL;

	AutoRedisReply()
	{

	}

	AutoRedisReply(redisReply* pRedisReply) // Conversion constructor
		:m_pRedisReply(pRedisReply)
	{
	}

	~AutoRedisReply()
	{
		Release();
		
	}

	void Release()
	{
		if (m_pRedisReply)
		{
			freeReplyObject(m_pRedisReply);
			m_pRedisReply = NULL;
		}
	}

	void Attach(redisReply* pRedisReply)
	{
		if (pRedisReply != m_pRedisReply) Release();
		m_pRedisReply = pRedisReply;
	}

	bool IsValid()
	{
		return m_pRedisReply != NULL;
	}

	bool IsReplyOK()
	{
		if (!m_pRedisReply) return false;
		return m_pRedisReply->type == REDIS_REPLY_STATUS;
	}
	
	bool IsReplyString()
	{
		if (!m_pRedisReply) return false;
		return m_pRedisReply->type == REDIS_REPLY_STRING;
	}

	std::string GetError()
	{
		std::string strError;
		if (!m_pRedisReply) return strError;

		strError = m_pRedisReply->str;
		return strError;
	}
};

redis连接类头文件

class ServerItem
{
public:
	std::string _strUrl;
	long		_nPost = 0;
};


class JSRedis
{
public:
	JSRedis();
	~JSRedis();

	bool Connect();
	bool IsConnect();
	redisReply* PopList();

	bool LoadConfig();
	void Release();

private:
	redisContext* m_pRedis = NULL;
	std::string m_strAdress;
	long		m_lPort = 0;

	std::string m_strPassword 
	std::vector<ServerItem> m_aryServer;	//多个服务器
	long m_lCurServerIndex = 0;
};

cpp实现

#include "pch.h"
#include <codecvt>
#include "JSRedis.h"
#include "JSLog.h"
#include "EnvironmentVariable.h"

std::wstring UTF8ToWString(const std::string& str)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
	return myconv.from_bytes(str);
}

JSRedis::JSRedis()
{

}


JSRedis::~JSRedis()
{
	Release();
}


void JSRedis::Release()
{
	if (m_pRedis)
	{
		redisFree(m_pRedis);
		m_pRedis = NULL;
	}
}


bool JSRedis::LoadConfig()
{
	const CString& strIni = EnvironmentVariable::GetInstance().GetIniPath();
	std::string strValue;
	TCHAR szValue[1024] = { 0 };
	
	::GetPrivateProfileString(L"Redis", L"Password", L"", szValue, ARRAYSIZE(szValue) - 1, strIni);
	m_strPassword = WStringToUTF8(szValue);

	//配置多个服务器
	m_aryServer.clear();
	int nCount= ::GetPrivateProfileInt(L"Redis", L"ServerCount", 0, strIni);
	CString strKey;
	for (int i = 0; i < nCount; ++i)
	{
		ServerItem item;

		strKey.Format(L"Server_Url_%d",i);
		::GetPrivateProfileString(L"Redis", strKey, L"", szValue, ARRAYSIZE(szValue) - 1, strIni);
		strValue = WStringToUTF8(szValue);
		if (strValue.empty()) continue; 
		item._strUrl = strValue;

		strKey.Format(L"Server_Port_%d", i);
		nValue = ::GetPrivateProfileInt(L"Redis", strKey, 0, strIni);
		if (nValue <= 0) continue;
		item._nPost = nValue;

		m_aryServer.push_back(item);
	}

	return true;
}

bool JSRedis::Connect()
{
	if (m_aryServer.empty()) return false;
	
	int nIndex = m_lCurServerIndex % m_aryServer.size();
	const auto& item = m_aryServer[nIndex];
	m_strAdress = item._strUrl;
	m_lPort = item._nPost;

	TRACE_DEBUG(L"[JSRedis::Connect] start connect %s:%d, nIndex=%d", UTF8ToWString(m_strAdress).c_str(), m_lPort, nIndex);

	redisContext* pRedis = redisConnect(m_strAdress.c_str(), m_lPort);
	if (!pRedis || pRedis->err)
	{
		TRACE_WARNING(L"[JSRedis::Connect] %s:%d, connect failed", UTF8ToWString(m_strAdress).c_str(), m_lPort);
		m_lCurServerIndex ++;
		if (pRedis) redisFree(pRedis);
		return false;
	}

	{
		AutoRedisReply reply = (redisReply*)redisCommand(pRedis, "AUTH %s", m_strPassword.c_str());
		if (!reply.IsValid())
		{
			redisFree(pRedis);
			return false;
		}

		if (!reply.IsReplyOK())
		{
			TRACE_WARNING(L"[JSRedis::Connect] %s:%d, password error.", UTF8ToWString(m_strAdress).c_str(), m_lPort);
			redisFree(pRedis);
			return false;
		}
	}

	{	//查询主从
		AutoRedisReply reply = (redisReply*)redisCommand(pRedis, "info replication");
		if (!reply.IsValid())
		{
			redisFree(pRedis);
			return false;
		}
		if (!reply.IsReplyString())
		{
			m_lCurServerIndex++;
			redisFree(pRedis);
			return false;
		}

		std::string strInfo = reply.m_pRedisReply->str;
		TRACE_NORMAL(L"[JSRedis::Connect] %s:%d,info replication:%s ", UTF8ToWString(m_strAdress).c_str(), m_lPort, UTF8ToWString(strInfo).c_str());
		if (strInfo.find("role:master") == std::string::npos)	//从的过滤掉
		{
			TRACE_WARNING(L"[JSRedis::Connect] %s:%d, is not 'role:master'.", UTF8ToWString(m_strAdress).c_str(), m_lPort);
			m_lCurServerIndex++;
			redisFree(pRedis);
			return false;
		}
	}

	{
		AutoRedisReply reply = (redisReply*)redisCommand(pRedis, "select %d", 12);
		if (!reply.IsValid())
		{
			redisFree(pRedis);
			return false;
		}
		if (!reply.IsReplyOK())
		{
			TRACE_WARNING(L"[JSRedis::Connect] %s:%d, select 12 error.", UTF8ToWString(m_strAdress).c_str(), m_lPort);
			redisFree(pRedis);
			return false;
		}
	}

	m_pRedis = pRedis;

	TRACE_DEBUG(L"[JSRedis::Connect] connect %s:%d success, nIndex=%d", UTF8ToWString(m_strAdress).c_str(), m_lPort, nIndex);

	return true;
}

bool JSRedis::IsConnect()
{
	return m_pRedis != NULL;
}

redisReply* JSRedis::PopList()
{
	std::string strKey = "队列名字"
	return (redisReply*)redisCommand(m_pRedis, "RPOP %s", strKey.c_str());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2209025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【鸟类识别系统】Python+卷积神经网络算法+人工智能+深度学习+ResNet50算法+计算机课设项目

一、介绍 鸟类识别系统。本系统采用Python作为主要开发语言&#xff0c;通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型&#xff0c;然后进行模型的迭代训练&#xff0c;得到一个识别精度较高的模型&#xff0c;然后在…

ORA-65096:公用用户名或角色名无效

CREATE USER DATA_SHARING IDENTIFIED BY "Ab2"; Oracle建立用户的的时候&#xff0c;可能会出现一直提示 ORA-65096:公用用户名或角色名无效&#xff1b; 我查了一下&#xff0c;好像是 oracle 12版本及以上版本的特性&#xff0c;用户名必须加c##或者C##前缀才能创…

对ElementPlus的el-select二次封装,添加分页和搜索功能,实现一个自定义的下拉选择框

组件展示效果图 在 Vue3 的 elementPlus项目中&#xff0c;我们经常需要使用下拉选择框 (el-select) 来展示大量数据。然而&#xff0c;默认情况下 el-select 不支持分页和搜索功能。本文将介绍如何通过二次封装 el-select 组件来实现这一需求&#xff0c;并使用自定义的 Hook …

一周热门|OpenAI 回击马斯克:为了自己的竞争优势,不断骚扰我们;微软、清华团队提出 Diff Transformer

「一周热门」将从【企业动态】【技术前瞻】【政策法规】【专家观点】四部分&#xff0c;带你快速跟进大模型行业热门动态。 企业动态 OpenAI 回击马斯克&#xff1a;为了自己的竞争优势&#xff0c;他不断骚扰我们 日前&#xff0c;OpenAI 指控马斯克在一场法律诉讼中对其进行…

谷歌浏览器 文件下载提示网络错误

情况描述&#xff1a; 谷歌版本&#xff1a;129.0.6668.90 (正式版本) &#xff08;64 位&#xff09; (cohort: Control)其他浏览器&#xff0c;比如火狐没有问题&#xff0c;但是谷歌会下载失败&#xff0c;故推断为谷歌浏览器导致的问题小文件比如1、2M会成功&#xff0c;大…

基于Transformer的诗句生成

基于Transformer的诗句生成 前言相关介绍Transformer一、基本原理与结构二、关键技术三、应用领域四、优缺点 Transformer应用&#xff1a;诗句生成优缺点 前提条件实验环境基于Transformer的诗句生成准备数据集读取数据集分割数据集设置相关参数创建自己DataSet对象定义网络模…

双十一速购清单!如何才能挑到性价比高的宠物空气净化器

对于很多上班族而言&#xff0c;平时都不敢大手大脚的花钱&#xff0c;甚至很想将一份钱掰成两份来用&#xff0c;所以双十一是很多人都不会错过的购物狂欢节。 当然&#xff0c;我这个996的社畜也一样&#xff0c;而且我还养了一只爱掉毛的猫咪&#xff0c;每天下班回去都看到…

光路科技TSN交换机和电力专用交换机即将亮相第31届中国国际电力设备及技术展览会

在全球能源领域正经历深刻转型之际&#xff0c;可再生能源技术的飞跃进步正为电力行业的未来开辟新径。太阳能、风能等绿色能源&#xff0c;凭借其无可比拟的优势&#xff0c;正稳步取代化石燃料&#xff0c;成为电力行业的主流趋势。多国政府积极响应&#xff0c;出台多项政策…

日均千万订单的交易平台设计稿

业务背景 平台主要售卖电子商品和少量特定的实物商品。 经营模式&#xff0c;主要分为平台商家和自营店&#xff0c;自营店的流量占整个平台业务的50%以上&#xff0c;我负责自营店交易履约相关业务。 以前的架构&#xff0c;平台交易和履约中心是所有流量共享&#xff0c;在…

day01-Qt5入门

day01-Qt5入门 1.下载Qtcreate 官网地址&#xff1a;http://qt-project.org/downloads 2.配置环境变量 将类似于 D:\Qt\Qt5.1.1\5.1.1\mingw48_32\bin 的目录添加到环境变量中 3.创建一个新项目 输入自己的项目名称&#xff0c;后面默认下一部 4.运行第一个项目 在窗口…

计算机网络:数据链路层 —— PPP 点对点协议

文章目录 PPP 帧PPP帧的格式PPP帧的透明传输面向字节的异步链路面向比特的同步链路 PPP帧的差错检测 PPP 的工作状态 点对点协议&#xff08;Point-to-Point Protocol&#xff0c;PPP&#xff09;是目前使用最广泛的点对点数据链路层协议&#xff0c;用于在两个节点之间进行数据…

10.12面试题

代理模式 为什么需要代理模式&#xff1f; 1.中介隔离 客户类不想或者不能直接引用委托对象&#xff0c;需要使用代理类作为中介&#xff0c;需要代理类和委托对象都实现同一接口 2.满足开闭原则 若客户类需要委托对象新增某些功能&#xff0c;就需要代理类在调用委托对象…

【ProtoBuf】基础使用与编译

文章目录 ProtoBuf的使用基本使用指定proto3语法package声明符定义消息(message)定义消息字段字段唯一编号 编译序列化与反序列化序列化与反序列化使用 ProtoBuf的使用 流程如下&#xff1a; 编写 .proto文件&#xff0c;定义结构对象(message)及属性内容使用 protoc 编译器编…

常用类(二)--String类的简单总结

文章目录 1.基本介绍1.1创建对象1.2找到对应下标的字符1.3找到对应字符的下标1.4指定位置开始遍历1.5反向进行遍历1.6大小写之间的转换1.7字符串转换为数组1.8元素的替换1.9字符串的分割1.10字符串的截取 2.StringBuilder和StringBuffer2.1 StringBuilder的引入2.2面试题目 1.基…

拆解学习【无线充,EMMC,锂电池电量计,OTA】(二)

主要学习到了&#xff1a;无线充&#xff0c;EMMC&#xff0c;手表CPU方案&#xff0c;锂电池电量计&#xff0c;OTA。 无线充电功能是产品的核心卖点之一&#xff0c;充电头网通过拆解发现&#xff0c;手表内部使用恒玄BES2500BP智能手表单芯片解决方案&#xff0c;内置四核C…

BetterZip怎么导入文件进行压缩?苹果解压软件怎么用?

BetterZip作为苹果系统常用的压缩文件软件之一&#xff0c;具有使用方便、压缩导出格式多、兼容性强等特点。我们要使用BetterZip进行文件压缩时&#xff0c;首先需要将文件导入到BetterZip才可以。 关于BetterZip的文件导入方式&#xff0c;主要有几种&#xff0c;今天我来给…

垂直AI大模型行业全景分析及发展趋势研究报告

2024-10-12调研咨询机构环洋市场咨询出版的【全球垂直AI大模型行业总体规模、主要厂商及IPO上市调研报告&#xff0c;2024-2030】只要调研全球垂直AI大模型总体规模&#xff0c;主要地区规模&#xff0c;主要企业规模和份额&#xff0c;主要产品分类规模&#xff0c;下游主要应…

每日一题|3158. 求出出现两次数字的 XOR 值|哈希

题目给的范围很小&#xff0c;50以内&#xff0c;所以什么数据结构都可以。 这里采用set来维护访问过的数字&#xff0c;利用哈希来提升时间效率。 class Solution:def duplicateNumbersXOR(self, nums: List[int]) -> int:visited set()l []res 0for i in nums:if i i…

游戏如何应对薅羊毛问题

在大众眼里&#xff0c;“薅羊毛”是指在电商领域&#xff0c;“羊毛党”利用平台、商家的促销规则&#xff0c;低价获取商品和服务的行为。如前不久“小天鹅被一夜薅走7000万”的案例震惊全网。 然而实际上&#xff0c;“薅羊毛”现象不仅存在于电商场景&#xff0c;在游戏中…

【Unity】TextMeshPro 3.0.9无法显示emoji表情问题

需要下载TextMeshPro 3.2.x-pre.xxx版本&#xff0c;重新生成Sprite Asset文件解决 注意&#xff1a;若Package Manager没有搜到pre版本&#xff0c;那么可以去github下载到本地&#xff0c;再解压后&#xff0c;将文件夹移动到工程Packages文件夹下&#xff0c;然后打开Packa…