前言
最近一直在学习redis,通过c/cpp来执行redis命令,使用的是hiredis客户端来实现的。
先简单贴一下代码
头文件
#include <vector>
#include <string>
#include <hiredis/hiredis.h>
typedef enum en_redisResultType
{
redis_reply_invalid = -1,
redis_reply_string,
redis_reply_integer,
redis_reply_array,
redis_reply_null
}redisResultType;
typedef struct st_redisResult
{
int type;
int inter;
std::string strdata;
std::vector<std::string> vecdata;
}redisResult;
class CRedisBase
{
public:
CRedisBase(const char *szip, int port, const char *szpwd, int dbname);
CRedisBase(void);
~CRedisBase(void);
int open_redis();
int close_redis();
int set_redis(const char *szcmd);
int set_redis_datas(std::vector<std::string> vcmd);
int get_redis(const char *szcmd, redisResult &result);
int get_redis_datas(std::vector<std::string> vcmd, std::vector<redisResult> &vresult);
int setConfig(const char *szip, int port, const char *szpwd, int dbname);
private:
redisContext *m_redis;
std::string m_strip;
std::string m_strpasswd;
int m_port;
int m_db;
int free_redis_reply(redisReply *reply);
int auth_redis(const char *szpwd);
int set_redis_pipeline(std::vector<std::string> vcmd, std::vector<int> &vstatus);
int get_redis_pipeline(std::vector<std::string> vcmd, std::vector<redisResult> &vresult);
};
代码
#include "redisbase.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
初始化操作
CRedisBase::CRedisBase(const char *szip, int port, const char *szpwd, int dbname)
{
m_redis = NULL;
setConfig(szip, port, szpwd, dbname);
}
CRedisBase::CRedisBase()
{
m_redis = NULL;
}
CRedisBase::~CRedisBase(void)
{
close_redis();
}
int CRedisBase::setConfig(const char *szip, int port, const char *szpwd, int dbname)
{
m_strip = szip;
m_strpasswd = szpwd;
m_port = port;
m_db = dbname;
return 0;
}
建立redis连接
int CRedisBase::open_redis()
{
close_redis();
int ret = -1;
struct timeval timeout = {1, 500000};// 1.5 seconds
for (int i = 0; i < 10; i ++)
{
m_redis = redisConnectWithTimeout(m_strip.c_str(), m_port, timeout);
if (m_redis == NULL || m_redis->err)
{
if (m_redis)
{
printf("connection redis %s:%d error:%s
", m_strip.c_str(), m_port, m_redis->errstr);
close_redis();
}
else
{
printf("connection redis %s:%d error:can't allocate redis context
",m_strip.c_str(), m_port);
}
sleep(3);
}
else
{
if(auth_redis(m_strpasswd.c_str()))
{
close_redis();
printf("connection redis %s:%d error: auth error
", m_strip.c_str(), m_port);
}
else
{
printf("connection redis %s:%d success
", m_strip.c_str(), m_port);
char szcmd[64]= {0};
snprintf(szcmd,sizeof(szcmd),"select %d", m_db);
printf("select db:%d
", m_db);
set_redis(szcmd);
ret = 0;
break;
}
}
}
return ret;
}
认证
int CRedisBase::auth_redis(const char *szpwd)
{
int ret = 0;
redisReply *reply = (redisReply *)redisCommand(m_redis, "AUTH %s", szpwd);
if (reply == NULL)
{
printf("AUTH error
");
return -1;
}
if (reply->type != REDIS_REPLY_STATUS)
{
printf("AUTH error: type [%d]
", reply->type);
ret = -1;
}
else
{
if (strcmp(reply->str, "OK") == 0)
{
printf("AUTH success [%s]
", reply->str);
}
else
{
printf("AUTH error: [%s]
", reply->str);
ret = -1;
}
}
return ret;
}
关闭操作
关闭redis连接
int CRedisBase::close_redis()
{
if (m_redis)
{
redisFree(m_redis);
m_redis = NULL;
}
return 0;
}
释放reply
int CRedisBase::free_redis_reply(redisReply *reply)
{
if (reply)
{
freeReplyObject(reply);
reply = NULL;
}
return 0;
}
数据操作
hiredis通过redisCommand接口获取数据后,数据保存在redisReply 结构体指针中,通过判断结构体的type成员类型,来获取相对应的数据。
为了防止断线,若redisReply 结构体指针为NULL时,重新连接redis
向redis设置数据
int CRedisBase::set_redis(const char *szcmd)
{
if (szcmd == NULL)
return -1;
if (m_redis == NULL)
{
if (open_redis())
return -1;
}
redisReply *reply = (redisReply *)redisCommand(m_redis, szcmd);
if (reply == NULL)
{
close_redis();
open_redis();
reply = (redisReply *)redisCommand(m_redis, szcmd);
if (reply == NULL)
{
printf("exec [%s] error
", szcmd);
return -1;
}
}
//printf("##########################exec [%s]
", szcmd);
int ret = 0;
switch(reply->type)
{
case REDIS_REPLY_STATUS:
if (strcmp(reply->str, "OK") == 0)
ret = 0;
else
ret = -1;
printf("[%s] status [%s]
", szcmd, reply->str);
break;
case REDIS_REPLY_ERROR:
ret = -1;
printf("[%s] error [%s]
", szcmd, reply->str);
break;
case REDIS_REPLY_STRING:
ret = 0;
printf("[%s] set result type:string
", szcmd);
break;
case REDIS_REPLY_INTEGER:
ret = 0;
printf("[%s] set result type:integer:%d
", szcmd, reply->integer);
break;
case REDIS_REPLY_ARRAY:
ret = 0;
printf("[%s] set result type:array
", szcmd);
break;
case REDIS_REPLY_NIL:
ret = 0;
printf("[%s] set result type:null
", szcmd);
break;
default:
ret = -1;
printf("[%s] set error
", szcmd);
break;
}
free_redis_reply(reply);
return ret;
}
向redis获取数据
int CRedisBase::get_redis(const char *szcmd, redisResult &result)
{
if (szcmd == NULL)
return NULL;
if (m_redis == NULL)
{
if (open_redis())
return -1;
}
result.type = redis_reply_invalid;
result.inter = 0;
redisReply *reply = (redisReply *)redisCommand(m_redis, szcmd);
if (reply == NULL)
{
close_redis();
open_redis();
reply = (redisReply *)redisCommand(m_redis, szcmd);
if (reply == NULL)
{
printf("exec [%s] error
", szcmd);
return -1;
}
}
//printf("##########################exec [%s]
", szcmd);
int ret = 0;
switch(reply->type)
{
case REDIS_REPLY_STATUS:
ret = -1;
printf("[%s] status [%s]
", szcmd, reply->str);
break;
case REDIS_REPLY_ERROR:
ret = -1;
printf("[%s] error [%s]
", szcmd, reply->str);
break;
case REDIS_REPLY_STRING:
ret = 0;
result.type = redis_reply_string;
result.strdata = reply->str;
printf("[%s] get string
", szcmd);
break;
case REDIS_REPLY_INTEGER:
ret = 0;
result.type = redis_reply_integer;
result.inter = reply->integer;
printf("[%s] get integer
", szcmd);
break;
case REDIS_REPLY_ARRAY:
ret = 0;
result.type = redis_reply_array;
for (int i = 0; i < reply->elements; i ++)
{
result.vecdata.push_back(reply->element[i]->str);
}
printf("[%s] get array
", szcmd);
break;
case REDIS_REPLY_NIL:
ret = 0;
result.type = redis_reply_null;
printf("[%s] get null
", szcmd);
break;
default:
ret = -1;
result.type = redis_reply_invalid;
printf("[%s] get error
", szcmd);
break;
}
free_redis_reply(reply);
return ret;
}
通过pipeline批量向redis设置数据
int CRedisBase::set_redis_datas(std::vector<std::string> vcmd)
{
std::vector<int> vstatus;
if (set_redis_pipeline(vcmd, vstatus))
{
close_redis();
open_redis();
if (set_redis_pipeline(vcmd, vstatus))
{
printf("exec set redises error
");
return -1;
}
}
return 0;
}
int CRedisBase::set_redis_pipeline(std::vector<std::string> vcmd, std::vector<int> &vstatus)
{
if (vcmd.empty())
return 0;
if (m_redis == NULL)
{
if (open_redis())
return -1;
}
for (int i = 0; i < vcmd.size(); i ++)
{
redisAppendCommand(m_redis, vcmd[i].c_str());
}
for (int i = 0; i < vcmd.size(); i ++)
{
int ret = -1;
redisReply *reply = NULL;
if (redisGetReply(m_redis, (void **)&reply) == REDIS_OK && reply != NULL)
if (ret == REDIS_OK && reply != NULL)
{
switch(reply->type)
{
case REDIS_REPLY_STATUS:
if (strcmp(reply->str, "OK") == 0)
ret = 0;
else
ret = -1;
printf("[%s] status [%s]
", vcmd[i].c_str(), reply->str);
break;
case REDIS_REPLY_ERROR:
ret = -1;
printf("[%s] error [%s]
", vcmd[i].c_str(), reply->str);
break;
case REDIS_REPLY_STRING:
ret = 0;
printf("[%s] set result type:string
", vcmd[i].c_str());
break;
case REDIS_REPLY_INTEGER:
ret = 0;
printf("[%s] set result type:integer:%d
", vcmd[i].c_str(), reply->integer);
break;
case REDIS_REPLY_ARRAY:
ret = 0;
printf("[%s] set result type:array
", vcmd[i].c_str());
break;
case REDIS_REPLY_NIL:
ret = 0;
printf("[%s] set result type:null
", vcmd[i].c_str());
break;
default:
ret = -1;
printf("[%s] set error
", vcmd[i].c_str());
break;
}
}
else
{
freeReplyObject(reply);
reply = NULL;
return -1;
}
freeReplyObject(reply);
reply = NULL;
vstatus.push_back(ret);
}
return 0;
}
通过pipeline批量获取数据
int CRedisBase::get_redis_datas(std::vector<std::string> vcmd, std::vector<redisResult> &vresult)
{
if (get_redis_pipeline(vcmd, vresult))
{
close_redis();
open_redis();
if (get_redis_pipeline(vcmd, vresult))
{
printf("exec get redises error
");
return -1;
}
}
return 0;
}
int CRedisBase::get_redis_pipeline(std::vector<std::string> vcmd, std::vector<redisResult> &vresult)
{
if (vcmd.empty())
return -1;
if (m_redis == NULL)
{
if (open_redis())
return -1;
}
for (int i = 0; i < vcmd.size(); i ++)
{
redisAppendCommand(m_redis, vcmd[i].c_str());
}
for (int i = 0; i < vcmd.size(); i ++)
{
int ret = -1;
redisResult result;
result.type = redis_reply_invalid;
result.inter = 0;
redisReply *reply = NULL;
if (redisGetReply(m_redis, (void **)&reply) == REDIS_OK && reply != NULL)
{
switch(reply->type)
{
case REDIS_REPLY_STATUS:
if (strcmp(reply->str, "OK") == 0)
ret = 0;
else
ret = -1;
printf("[%s] status [%s]
", vcmd[i].c_str(), reply->str);
break;
case REDIS_REPLY_ERROR:
ret = -1;
printf("[%s] error [%s]
", vcmd[i].c_str(), reply->str);
break;
case REDIS_REPLY_STRING:
ret = 0;
result.type = redis_reply_string;
result.strdata = reply->str;
printf("[%s] get string
", vcmd[i].c_str());
break;
case REDIS_REPLY_INTEGER:
ret = 0;
result.type = redis_reply_integer;
result.inter = reply->integer;
printf("[%s] get integer
", vcmd[i].c_str());
break;
case REDIS_REPLY_ARRAY:
ret = 0;
result.type = redis_reply_array;
for (int i = 0; i < reply->elements; i ++)
{
result.vecdata.push_back(reply->element[i]->str);
}
printf("[%s] get array
", vcmd[i].c_str());
break;
case REDIS_REPLY_NIL:
ret = 0;
result.type = redis_reply_null;
printf("[%s] get null
", vcmd[i].c_str());
break;
default:
ret = -1;
result.type = redis_reply_invalid;
printf("[%s] get error
", vcmd[i].c_str());
break;
}
}
else
{
freeReplyObject(reply);
reply = NULL;
return -1;
}
freeReplyObject(reply);
reply = NULL;
vresult.push_back(result);
}
return 0;
}