C++ 封装 hredis-win32 实现底层操作解耦,并实现自动重连

windows上操作redis貌似一直不是redis官方的主流想法,如果用C#操作的话,我推荐NServiceKit.Redis这个开源库来操作,但是如果你使用的是VC++操作redis,很抱歉并没有什么特别好用库可以非常方便的操作redis所有功能,经过精挑细选,我找到了

但是这个库也是有不少坑,尤其是编译过程中“”结构体成员对齐“”他默认选择的1字节对齐,所以你这样编译出来的lib文件对VC编译器大部分使用默认8字节对齐简直就是灾难。为了避免大家踩坑我这里放一个VS2013 MDd模式,默认结构对齐方式 编译 好的一个lib库给大家下载,免走编译坑。http://pan.baidu.com/s/1kVAxg0Z

剩下就废话不多说直接上我对这个库的二次封装代码吧。先看主函数调用效果(封装好后就是这么Easy使用)
注意hiredisD_VS2013.lib这个lib库要附加到工程里编译额(后续有时间一定放上完整能跑的工程到Csdn下载中心)

// PBHelper_hiredis-win32-Test.cpp : 定义控制台应用程序的入口点。
//

#include <iostream>
#include "src/hiredis/hiredishelper.h"
#include <vector>
int main()
{
	PBLIB::Redis::hiredisUtility redisclass;

	//redisclass.Start();// 内部异步实现了自动重连

	redisclass.Connect(1000);//开始连接Redis


	redisclass.Set("ABC", "123");//设置key
	redisclass.Set("QWE", "123456789", 4);//设置key

	std::string str;
	redisclass.Get("ABC", str);//获取key
	redisclass.LPush("listA", "123546");//压入一个list值
	redisclass.LPush("listA", "654321");//压入一个list值
	std::string popval;
	redisclass.LPop("listA", popval);//弹出一个list值

	std::vector<std::string> vec;
	redisclass.GetList("listA", vec);//获取一个list读到vector中

	return 0;
}
接下来直接上封装过程
#pragma once


#include <iostream>
#include <functional>
#include <mutex>
#include <vector>
namespace PBLIB
{
	namespace Redis
	{

		enum class PB_HIREDISUTILITY_EVENT
		{
			Connect = 100,
			TryConnect,
			DisConnect
		};

		class   hiredisUtility
		{
		public:
			typedef std::function<void(const char * msg, PB_HIREDISUTILITY_EVENT, void*)>  EventHandler;

			hiredisUtility();

			~hiredisUtility();

			void Start();

			void Connect(int millisecond);

			void Disonnect();

			bool Ping();

			bool CmdGetString(std::string &restr, const char *format, ...);

			bool CmdGetInteger(long long &val, const char *format, ...);

			bool  CmdAndEuqalString(const char * equalval, const char *format, ...);

			//Key,Value
			void Get(const char *key, std::string &restr);
			bool Set(const char *key, const std::string &valstr);
			bool Set(const char *key, char * buff, int size);


			//List
			long long LPush(const char * listId, char * buff, int size);
			long long LPush(const char * listId, const std::string &valstr);
		
			bool LPop(const char * listId, std::string &valstr);
			int LLen(const char * listId);
			bool LRange(const char * listId, int startingFrom, int endingAt,std::vector<std::string> &vec);

			bool GetList(const char * listId, std::vector<std::string> &vec);


			EventHandler evenhandler;
			std::mutex m_Cmdmutex;
		private:
			void* Cmd(const char *format, ...);
			bool IsAutoReconnect;
			char m_ip[15];
			int m_port;
			void * m_Context;

			
			std::string m_errorDetail;
		};
	}
}
#include "hiredishelper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exception>
#include <thread>

#include "WinSock2.h"
#include "../../external/hiredis-win32-master/include/hiredis.h"

#pragma comment(lib, "ws2_32.lib")



namespace PBLIB
{
	namespace Redis
	{
#define REDIS_REPLY_STR_OK "OK"


		hiredisUtility::hiredisUtility() :m_port(6379)
		{
			strcpy(m_ip, "127.0.0.1");
			m_Context = nullptr;
			evenhandler = nullptr;

			//main2();
		}

		hiredisUtility::~hiredisUtility()
		{
			IsAutoReconnect = false;//停止自动重连线程
		}

		//http://blog.csdn.net/gdutliuyun827/article/details/44339007

		bool hiredisUtility::Ping()
		{
			return CmdAndEuqalString("PONG", "PING");
		}

		//万能方案备用
		void* hiredisUtility::Cmd(const char *format, ...)
		{
			if (m_Context == nullptr) return NULL;

			redisContext *c = (redisContext*)m_Context;

			va_list ap;
			void *reply = NULL;
			va_start(ap, format);
			reply = redisvCommand(c, format, ap);
			va_end(ap);

			if (!c->err)
			{
				return reply;
			}
			return NULL;
		}

		bool hiredisUtility::CmdGetString(std::string &restr, const char *format, ...)
		{
			if (m_Context == nullptr) return false;

			std::lock_guard<std::mutex> locker(m_Cmdmutex);
			redisContext *c = (redisContext*)m_Context;

			va_list ap;
			void *reply = NULL;
			va_start(ap, format);
			reply = redisvCommand(c, format, ap);
			va_end(ap);

			if (!c->err)
			{
				bool IsErroring = false;
				bool flag = false;
				redisReply* r = (redisReply*)reply;
				if (r->type == REDIS_REPLY_STRING)
				{
					restr = r->str;
					flag = true;
				}
				if (r->type == REDIS_REPLY_ERROR)
				{
					IsErroring = true;
					m_errorDetail = r->str;
				}
				freeReplyObject(r);
				if (IsErroring)  throw std::exception(m_errorDetail.data());//直接丢错
				return flag;
			}
			return false;
		}

		bool hiredisUtility::CmdGetInteger(long long &val, const char *format, ...)
		{
			if (m_Context == nullptr) return false;

			std::lock_guard<std::mutex> locker(m_Cmdmutex);
			redisContext *c = (redisContext*)m_Context;

			va_list ap;
			void *reply = NULL;
			va_start(ap, format);
			reply = redisvCommand(c, format, ap);
			va_end(ap);

			if (!c->err)
			{
				bool IsErroring = false;
				bool flag = false;
				redisReply* r = (redisReply*)reply;
				if (r->type == REDIS_REPLY_INTEGER)
				{
					val = r->integer;
					flag = true;
				}
				if (r->type == REDIS_REPLY_ERROR)
				{
					IsErroring = true;
					m_errorDetail = r->str;
				}
				freeReplyObject(r);
				if (IsErroring)  throw std::exception(m_errorDetail.data());//直接丢错
				return flag;
			}
			return false;
		}

		bool hiredisUtility::CmdAndEuqalString(const char * equalval, const char *format, ...)
		{
			if (m_Context == nullptr) return false;
			std::lock_guard<std::mutex> locker(m_Cmdmutex);

			redisContext *c = (redisContext*)m_Context;

			va_list ap;
			void *reply = NULL;
			va_start(ap, format);
			reply = redisvCommand(c, format, ap);
			va_end(ap);

			if (!c->err)
			{
				bool IsErroring = false;
				bool flag = false;
				redisReply* r = (redisReply*)reply;
				if (r->str != NULL)
					flag = strcmp(equalval, r->str) == 0;//如果返回是str
				if (r->type == REDIS_REPLY_ERROR)
				{
					IsErroring = true;
					m_errorDetail = r->str;
				}
				freeReplyObject(r);
				if (IsErroring)  throw std::exception(m_errorDetail.data());//直接丢错
				return flag;
			}
			return false;
		}

		void hiredisUtility::Get(const char *key, std::string &restr)
		{
			CmdGetString(restr, "get %s", key);
		}

		bool hiredisUtility::Set(const char *key, const std::string &valstr)
		{
			return	CmdAndEuqalString(REDIS_REPLY_STR_OK, "set %b %b", key, strlen(key), valstr.data(), valstr.size());
		}

		bool hiredisUtility::Set(const char *key, char * buff, int size){
			return	CmdAndEuqalString(REDIS_REPLY_STR_OK, "set %b %b", key, strlen(key), buff, size);
		}



		long long hiredisUtility::LPush(const char * listId, char * buff, int size)
		{
			long long res = 0;
			CmdGetInteger(res, "LPush %b %b", listId, strlen(listId), buff, size);
			return res;
		}

		long long hiredisUtility::LPush(const char * listId, const std::string &valstr){

			long long res = 0;
			CmdGetInteger(res, "LPush %b %b", listId, strlen(listId), valstr.data(), valstr.size());
			return res;
		}

		bool hiredisUtility::LPop(const char * listId, std::string &valstr)
		{
			return CmdGetString(valstr, "LPop %s", listId);
		}

		void hiredisUtility::Connect(int millisecond)
		{
			if (m_Context != nullptr) return;

			int tv_sec = millisecond / 1000;
			int millisec = millisecond % 1000;
			long tv_usec = millisec * 1000;
			struct timeval timeout;
			timeout.tv_sec = tv_sec;
			timeout.tv_usec = tv_usec;

			redisContext  *c;
			c = redisConnectWithTimeout(m_ip, m_port, timeout);
			if (c != NULL && c->err)
			{
				redisFree(c);
				return;
			}

			m_Context = c;

			if (m_Context != nullptr)
				if (evenhandler != nullptr)
					evenhandler("Redis连接上", PB_HIREDISUTILITY_EVENT::Connect, NULL);
		}

		int hiredisUtility::LLen(const char * listId)
		{
			long long res = 0;
			CmdGetInteger(res, "LLen %b", listId, strlen(listId));
			return res;
		}

		bool hiredisUtility::LRange(const char * listId, int startingFrom, int endingAt, std::vector<std::string> &vec)
		{
			std::lock_guard<std::mutex> locker(m_Cmdmutex);
			void *reply = Cmd("LRange %s %d %d", listId, startingFrom, endingAt);
			if (reply == NULL) return false;
			bool IsErroring = false;
			bool flag = false;
			redisReply* r = (redisReply*)reply;
			if (r->type == REDIS_REPLY_ERROR)
			{
				IsErroring = true;
				m_errorDetail = r->str;
			}
			if (r->type == REDIS_REPLY_ARRAY)
			{
				flag = true;
				for (int j = 0; j < r->elements; j++)
				{
					std::string str = r->element[j]->str;
					vec.push_back(str);
				}
			}
			freeReplyObject(r);
			if (IsErroring)  throw std::exception(m_errorDetail.data());//直接丢错
			return flag;
		}

		bool hiredisUtility::GetList(const char * listId, std::vector<std::string> &vec){
			int len = LLen(listId);
			return LRange(listId, 0, len - 1, vec);
		}

		void hiredisUtility::Start()
		{
			IsAutoReconnect = true;
			std::thread th([this](){

				while (IsAutoReconnect)
				{
					std::chrono::milliseconds timespan(1000);
					std::this_thread::sleep_for(timespan);
					if (Ping() == false)
					{
						Disonnect();
						evenhandler("Redis尝试连接", PB_HIREDISUTILITY_EVENT::TryConnect, NULL);
						Connect(1000);
					}
				}
				Disonnect();
			});
			th.detach();
		}

		void hiredisUtility::Disonnect()
		{

			if (m_Context == nullptr) return;

			redisContext *c = (redisContext*)m_Context;
			if (c != NULL)
			{
				redisFree(c);
				m_Context = nullptr;
				evenhandler("Redis断开了", PB_HIREDISUTILITY_EVENT::Connect, NULL);
			}
		}


		//void redisFree(redisContext *c);










	}
}




  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值