以前有个windows c++项目要连redis,搞得还是挺麻烦的,现在整理了下把它分享出来
连接库用的是GitHub上开源的 MSOpenTech/redis,这个可以说是windows版的hiredis,没有多余的封装,很适合C++开发。
1、打开cmd 输入git clone https://github.com/MSOpenTech/redis.git <目标路径>
或者直接从GitHub上下载zip解压也行
2、打开msvs->RedisServer.sln,直接生成32/64位 release
3、新建解决方案,新建项目dll,我这把dll命名为Redis
建立dll是为了把自己项目和redis引入的头文件分隔开,避免冲突(目前来说是肯定有冲突的,win32fixes.h里面解决的就是冲突,但当时试了好像冲突没有解决完),而且使用更改的时候更简单、便捷
4、拷贝msvs->x64->Release->hiredis.lib、Win32_Interop.lib到项目Redis目录下
5、拷贝src->Win32_Interop和src->Win32_Interop->win32fixes.c、win32fixes.h和deps->hiredis到项目Redis目录下,并把hiredis->adapters那4个.h移动到hiredis中
6、在项目Redis下建立redis.h和redis.cpp 并引入win32fixes.c、win32fixes.h,若需要在多线程中使用同一个Redis对象,则需建立atomic_lock.h锁解决线程并行冲突的问题
7、先附上我封装的代码
redis.h
#pragma once
#include "hiredis/hiredis.h"
#define NO_QFORKIMPL //这一行必须加才能正常使用
#include "Win32_Interop\win32fixes.h"
#pragma comment(lib,"hiredis.lib")
#pragma comment(lib,"Win32_Interop.lib")
using namespace std;
class RedisBase
{
public:
virtual ~RedisBase(){};
virtual void Init() = 0;
virtual void Init(char* ip, int port) = 0;
virtual char* Command(char* cmd, bool needresult=false) = 0;
};
extern "C" _declspec(dllexport) RedisBase* GetInstance();
#include "redis.h"
#include
#include "atomic_lock.h"
using namespace std;
class Redis :public RedisBase
{
private:
redisContext *context;
Atomic_Lock lock;
public:
virtual void Init()
{
context = redisConnect("127.0.0.1", 6379);
redisEnableKeepAlive(context);
if (context->err) {
printf("Connection error: %s\n", context->errstr);
exit(1);
}
}
virtual void Init(char* ip, int port)
{
context = redisConnect(ip, port);
redisEnableKeepAlive(context);
if (context->err) {
printf("Connection error: %s\n", context->errstr);
exit(1);
}
}
virtual ~Redis()
{
redisFreeKeepFd(context);
redisFree(context);
}
virtual char* Command(char* cmd,bool needresult=false)
{
lock.Lock();
redisReply* reply = (redisReply *)redisCommand(context, cmd);
if (!needresult)
{
freeReplyObject(reply);
lock.UnLock();
return NULL;
}
char* result=NULL;
if(reply->len>0)
{
result = new char[reply->len+1];
memcpy(result, reply->str, reply->len);
result[reply->len] = '\0';
}
freeReplyObject(reply);
lock.UnLock();
return result;
}
};
RedisBase* GetInstance()
{
return new Redis();
}
atomic_lock.h
#pragma once
#include
#include
class Atomic_Lock
{
std::atomic_bool _lock = false;
bool _lockExp = true;
bool _unlockExp = false;
int status = 1;
public:
void Lock()
{
while (!atomic_compare_exchange_weak(&_lock, &_unlockExp, _lockExp))
{
Sleep(1);
}
}
void UnLock()
{
_lock = false;
}
void Discard()
{
status = 0;
}
int GetStatus() const
{
return status;
}
};
由于以后要引入dll直接使用,所以redis.h中定义的RedisBase就相当于接口,Redis继承RedisBase实现接口方法,然后采用工厂模式,RedisBase* GetInstance();去创建Redis对象,并返回RedisBase*,这样以后拷贝dll和引入redis.h 就能直接使用。我当初的设计是只建立N个Redis对象,然后用长连接,这样减小创建销毁对象和连接的开销,在Init初始化连接,并调用redisEnableKeepAlive(ctx)即可。我的封装也是很基础的,只封装了个virtual char* Command(char* cmd,bool needresult=false); 用于直接传递redis命令,并指定是否返回结果。若结果返回,返回的char* 指向堆,必须使用delete释放,切记!
9、生成Redis.dll
10、在此解决方案下建立自己的项目,我这是serv。创建redis.h
#pragma once
#include
using namespace std;
class RedisBase
{
public:
virtual ~RedisBase(){};
virtual void Init() = 0;
virtual void Init(char* ip, int port) = 0;
virtual char* Command(char* cmd, bool needresult=false) = 0;
};
//extern "C" _declspec(dllexport) void Test();
extern "C" _declspec(dllexport) RedisBase* GetInstance();
全局对象:
HINSTANCE redisDll;
RedisBase* redis[10];
void CreateRedisInstance()
{
typedef RedisBase*(*redisFunc)();
redisDll = LoadLibrary(_T("C:\\Redis.dll"));
if (redisDll == NULL)
{
cout << "load failed" << endl;
FreeLibrary(redisDll);
}
redisFunc getInstance = (redisFunc)GetProcAddress(redisDll, "GetInstance");
for (int i = 0; i < 10; i++) {
redis[i] = getInstance();
redis[i]->Init();
redis[i]->Command("AUTH xs84796815");
char temp[32];
sprintf_s(temp, "select %d", i);
redis[i]->Command(temp);
}
}
12、尽情使用吧!
例:
redis[0]->Command("SET 0 123");
char* result = redis[0]->Command(“GET 0”,true);
delete result;
13、释放 Redis对象
void ReleaseRedisInstance()
{
for(int i=0;i<10;i++)
{
delete redis[i];
}
FreeLibrary(redisDll);
}