• 【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库使用

  • 相关阅读:
    【leetcode】ZigZag——easy
    联合
    AddChildViewController
    imageWithRender(图片的渲染模式)
    13.范型函数的使用:将字典合并到当前字典
    12.代码获取命名空间名称,并创建相应的类(anyClass 应用)
    13.static 面向对象
    11.swift 单例
    swift String 扩展
    swift UIView 扩展
  • 原文地址:https://www.cnblogs.com/JesseTsou/p/10418439.html
Copyright © 2020-2023  润新知