C++ 封装 hredis-win32 实现底层操作解耦,并实现自动重连
2017-02-04 03:27
781 查看
windows上操作redis貌似一直不是redis官方的主流想法,如果用C#操作的话,我推荐NServiceKit.Redis这个开源库来操作,但是如果你使用的是VC++操作redis,很抱歉并没有什么特别好用库可以非常方便的操作redis所有功能,经过精挑细选,我找到了
开源库hredis-win32:https://github.com/texnician/hiredis-win32
但是这个库也是有不少坑,尤其是编译过程中“”结构体成员对齐“”他默认选择的1字节对齐,所以你这样编译出来的lib文件对VC编译器大部分使用默认8字节对齐简直就是灾难。为了避免大家踩坑我这里放一个VS2013 MDd模式,默认结构对齐方式 编译 好的一个lib库给大家下载,免走编译坑。http://pan.baidu.com/s/1kVAxg0Z
剩下就废话不多说直接上我对这个库的二次封装代码吧。先看主函数调用效果(封装好后就是这么Easy使用)
注意hiredisD_VS2013.lib这个lib库要附加到工程里编译额(后续有时间一定放上完整能跑的工程到Csdn下载中心)
完整源码工程VS2013 http://download.csdn.net/detail/lightspear/9762453
开源库hredis-win32:https://github.com/texnician/hiredis-win32
但是这个库也是有不少坑,尤其是编译过程中“”结构体成员对齐“”他默认选择的1字节对齐,所以你这样编译出来的lib文件对VC编译器大部分使用默认8字节对齐简直就是灾难。为了避免大家踩坑我这里放一个VS2013 MDd模式,默认结构对齐方式 编译 好的一个lib库给大家下载,免走编译坑。http://pan.baidu.com/s/1kVAxg0Z
剩下就废话不多说直接上我对这个库的二次封装代码吧。先看主函数调用效果(封装好后就是这么Easy使用)
注意hiredisD_VS2013.lib这个lib库要附加到工程里编译额(后续有时间一定放上完整能跑的工程到Csdn下载中心)
完整源码工程VS2013 http://download.csdn.net/detail/lightspear/9762453
// 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); } }
相关文章推荐
- C++对注册表常见操作的封装实现(三)
- C++ 简易string类实现(四)-自动操作引用次数
- C++对注册表常见操作的封装实现(四)
- C++对注册表常见操作的封装实现
- C++ 实现Mutex(底层用win32) 和 C++中析构过程 和常量性的大坑
- C++对注册表常见操作的封装实现(一)
- MySQL的C++封装实现数据库的创建,表的创建,数据库的读写操作
- [C++]MYSQL 数据库操作封装及连接池实现
- C++对注册表常见操作的封装实现
- C++对注册表常见操作的封装实现(二)
- C++对注册表常见操作的封装实现(五)
- 使用C#自动生成Word2003文档(通过操作COM组件实现)-转载
- 用 LotusScript 实现 Excel 报表的自动生成和操作
- .NET1.1下,使用C#自动生成Word2003文档(通过操作COM组件实现)
- 用 LotusScript 实现 Excel 报表的自动生成和操作
- 封装的一些实现图片水印与图片自动结合缩放的类
- Web C#2.0 DataSet和Reader封装组件实现自动多数据库切换(含组件源码和实例)
- 对posix线程机制的c++封装实现
- 利用反射和自定义特性实现基本数据存取操作自动获取
- 在ORACLE中实现后台自动执行的定时操作