開源庫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);
}
}