前言
最近一直在学习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 secondsfor (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\n", m_strip.c_str(), m_port, m_redis->errstr);close_redis();}else{printf("connection redis %s:%d error:can't allocate redis context\n",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\n", m_strip.c_str(), m_port);}else{printf("connection redis %s:%d success\n", m_strip.c_str(), m_port);char szcmd[64]= {0};snprintf(szcmd,sizeof(szcmd),"select %d", m_db);printf("select db:%d\n", 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\n");return -1;}if (reply->type != REDIS_REPLY_STATUS){printf("AUTH error: type [%d]\n", reply->type);ret = -1;}else{if (strcmp(reply->str, "OK") == 0){printf("AUTH success [%s]\n", reply->str);}else{printf("AUTH error: [%s]\n", 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\n", szcmd);return -1;}}//printf("##########################exec [%s]\n", szcmd);int ret = 0;switch(reply->type){case REDIS_REPLY_STATUS:if (strcmp(reply->str, "OK") == 0)ret = 0;elseret = -1;printf("[%s] status [%s]\n", szcmd, reply->str);break;case REDIS_REPLY_ERROR:ret = -1;printf("[%s] error [%s]\n", szcmd, reply->str);break;case REDIS_REPLY_STRING:ret = 0;printf("[%s] set result type:string\n", szcmd);break;case REDIS_REPLY_INTEGER:ret = 0;printf("[%s] set result type:integer:%d\n", szcmd, reply->integer);break;case REDIS_REPLY_ARRAY:ret = 0;printf("[%s] set result type:array\n", szcmd);break;case REDIS_REPLY_NIL:ret = 0;printf("[%s] set result type:null\n", szcmd);break;default:ret = -1;printf("[%s] set error\n", 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\n", szcmd);return -1;}}//printf("##########################exec [%s]\n", szcmd);int ret = 0;switch(reply->type){case REDIS_REPLY_STATUS:ret = -1;printf("[%s] status [%s]\n", szcmd, reply->str);break;case REDIS_REPLY_ERROR:ret = -1;printf("[%s] error [%s]\n", szcmd, reply->str);break;case REDIS_REPLY_STRING:ret = 0;result.type = redis_reply_string;result.strdata = reply->str;printf("[%s] get string\n", szcmd);break;case REDIS_REPLY_INTEGER:ret = 0;result.type = redis_reply_integer;result.inter = reply->integer;printf("[%s] get integer\n", 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\n", szcmd);break;case REDIS_REPLY_NIL:ret = 0;result.type = redis_reply_null;printf("[%s] get null\n", szcmd);break;default:ret = -1;result.type = redis_reply_invalid;printf("[%s] get error\n", 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\n");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;elseret = -1;printf("[%s] status [%s]\n", vcmd[i].c_str(), reply->str);break;case REDIS_REPLY_ERROR:ret = -1;printf("[%s] error [%s]\n", vcmd[i].c_str(), reply->str);break;case REDIS_REPLY_STRING:ret = 0;printf("[%s] set result type:string\n", vcmd[i].c_str());break;case REDIS_REPLY_INTEGER:ret = 0;printf("[%s] set result type:integer:%d\n", vcmd[i].c_str(), reply->integer);break;case REDIS_REPLY_ARRAY:ret = 0;printf("[%s] set result type:array\n", vcmd[i].c_str());break;case REDIS_REPLY_NIL:ret = 0;printf("[%s] set result type:null\n", vcmd[i].c_str());break;default:ret = -1;printf("[%s] set error\n", 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\n");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;elseret = -1;printf("[%s] status [%s]\n", vcmd[i].c_str(), reply->str);break;case REDIS_REPLY_ERROR:ret = -1;printf("[%s] error [%s]\n", 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\n", vcmd[i].c_str());break;case REDIS_REPLY_INTEGER:ret = 0;result.type = redis_reply_integer;result.inter = reply->integer;printf("[%s] get integer\n", 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\n", vcmd[i].c_str());break;case REDIS_REPLY_NIL:ret = 0;result.type = redis_reply_null;printf("[%s] get null\n", vcmd[i].c_str());break;default:ret = -1;result.type = redis_reply_invalid;printf("[%s] get error\n", vcmd[i].c_str());break;}}else{freeReplyObject(reply);reply = NULL;return -1;}freeReplyObject(reply);reply = NULL;vresult.push_back(result);}return 0;
}
参考文章
封装hiredis
redis 使用-hiredis库使用