Windows C++ Redis

以前有个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中

Windows C++ Redis_第1张图片

Windows C++ Redis_第2张图片

6、在项目Redis下建立redis.h和redis.cpp 并引入win32fixes.c、win32fixes.h,若需要在多线程中使用同一个Redis对象,则需建立atomic_lock.h锁解决线程并行冲突的问题

Windows C++ Redis_第3张图片


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();


redis.cpp

#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;
	}
};


8、代码说明:

由于以后要引入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();

11、在main中#include "redis.h",并在 main 中调用 CreateRedisInstance(); 我这创建了10个redis对象,首先发送 auth xxx,并select i 对应的数据库

全局对象:

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);
}




你可能感兴趣的:(C/C++)