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

最近需要在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());
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HQChart

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值