【redis】c/c++操作redis(对于hiredis的封装)

前言

最近一直在学习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;
}

参考文章

封装hiredis
redis 使用-hiredis库使用

原文地址:https://www.cnblogs.com/JesseTsou/p/10418439.html