个人redis连接池,hiredis,欢迎共同探讨

本文档展示了使用hiredis库实现的一个名为MyRedisPool的Redis连接池,包括初始化连接、获取连接、发布/订阅、管道操作等功能。通过连接池管理Redis连接,提高了代码的复用性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifndef _MY_REDIS_POOL_HPP_
#define _MY_REDIS_POOL_HPP_


#include <cstdio>
#include <cstdlib>
#include <string>
#include <time.h>
#include <vector>
#include <queue>
#include<mutex>
#include <hiredis/hiredis.h>

#ifdef _WIN32
//编译 hiredis 会生成这2个库
#pragma comment(lib, "hiredis.lib")
#pragma comment(lib,"Win32_Interop.lib")
#endif // _WIN32

typedef struct RedisNode
{
    int id;
    redisContext *c;
    bool isUsed;
};

class MyRedisPool
{
public:
    static MyRedisPool& GetInstance();
protected:
    MyRedisPool();
    ~MyRedisPool();
private:
    MyRedisPool(const MyRedisPool& rhs) {}
    MyRedisPool& operator = (const MyRedisPool& rhs) {}

public:
    bool InitConnect(std::string const& host, std::string const& password, int port,int count);
    RedisNode& GetConnect(bool& isSuccess);
    bool GetRedisReply(redisReply *&reply);
    bool AddConnect();
    bool DisConnect();
    bool BackConnect(RedisNode& node);
    bool GetLPOP(std::string const&key, std::string&value, int dbName);
    bool SetLPUSH(std::string const&key, std::string&value, int dbName);
    bool GetLRange(std::string const&key, int dbName, int start, int end, std::vector<std::string>& result);
    bool SetString(std::string const&key, std::string&value, int dbName);
    bool GetString(std::string const&key, std::string&value, int dbName);
    bool SetInt(std::string const&key, int &number, int dbName);
    bool GetInt(std::string const&key, int &number, int dbName);
    bool SUBSCRIBE(std::string const&theme);
    bool PUBLISH(std::string const& theme, std::string const& content);
    bool GetLPOPByPipeline(std::string const&key, std::string&value, int dbName);
    bool SetLPUSHByPipeline(std::string const&key, std::string&value, int dbName);
    bool GetLRangeByPipeline(std::string const&key, int dbName, int start, int end, std::vector<std::string>& result);
    bool SetStringByPipeline(std::string const&key, std::string&value, int dbName);
    bool GetStringByPipeline(std::string const&key, std::string&value, int dbName);
    bool SetIntByPipeline(std::string const&key, int &number, int dbName);
    bool GetIntByPipeline(std::string const&key, int &number, int dbName);
protected:
    bool CreateOneConnect(redisContext *&c);
private:
    std::string m_Host;
    int m_Port;
    std::string m_PassWord;
    int m_MaxConnects;
    int m_CurConnects;
    std::vector<RedisNode> m_RedisVec;
    std::queue<int> m_QueueId;
    std::mutex m_Lock;
    std::mutex m_PrintLock;
    bool m_runing;
};

MyRedisPool::MyRedisPool()
{
    m_runing = true;
}
MyRedisPool::~MyRedisPool()
{
    DisConnect();
    printf("析构了...\n");
}
bool MyRedisPool::GetRedisReply(redisReply *&reply)
{
    if (reply)
    {
        if (reply->type == REDIS_REPLY_ERROR)
        {
            std::lock_guard<std::mutex> lck(m_PrintLock);
            fprintf(stderr, "error: %s\n", reply->str);
            freeReplyObject(reply);
            return false;
        }
        else
        {
            return true;
        }
    }
    else
    {
        return false;
    }
}
bool MyRedisPool::GetLPOPByPipeline(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "LPOP %s", key.data());
        redisReply *reply = NULL;
        redisGetReply(node.c,(void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                value = reply->str;
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::SetLPUSHByPipeline(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "LPUSH %s %s", key.data(), value.data());
        redisReply *reply = NULL;
        redisGetReply(node.c, (void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::GetLRangeByPipeline(std::string const&key, int dbName, int start, int end, std::vector<std::string>& result)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "LRANGE %s %d %d", key.data(), start, end);
        redisReply *reply = NULL;
        redisGetReply(node.c, (void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->type == REDIS_REPLY_ARRAY) {
                    for (int j = 0; j < reply->elements; j++) {
                        //printf("%u) %s\n", j, reply->element[j]->str);
                        result.push_back(reply->element[j]->str);
                    }
                }
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::SetStringByPipeline(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "SET %s %s", key.data(), value.data());
        redisReply *reply = NULL;
        redisGetReply(node.c, (void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::GetStringByPipeline(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "GET %s", key.data());
        redisReply *reply = NULL;
        redisGetReply(node.c, (void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->len > 0)
                {
                    value = reply->str;
                }
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::SetIntByPipeline(std::string const&key, int &number, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "SET %s %s", key.data(), number);
        redisReply *reply = NULL;
        redisGetReply(node.c, (void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::GetIntByPipeline(std::string const&key, int &number, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisAppendCommand(node.c, "SELECT %d", dbName);
        redisAppendCommand(node.c, "GET %s", key.data());
        redisReply *reply = NULL;
        redisGetReply(node.c, (void**)&reply);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            redisGetReply(node.c, (void**)&reply);
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->len > 0)
                {
                    number = std::atoi(reply->str);
                }
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
}
bool MyRedisPool::SetLPUSH(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
        
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "LPUSH %s %s", key.data(),value.data());
            ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::GetLPOP(std::string const&key, std::string&value,int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
            value = reply->str;
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "LPOP %s", key.data());
            ret = GetRedisReply(reply);
            if (ret)
            {
                value = reply->str;
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::GetLRange(std::string const&key, int dbName, int start, int end, std::vector<std::string>& result)
{
    bool isSuccess = false;
    bool ret = false;
    result.clear();
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "LRANGE %s %d %d", key.data(),start,end);
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->type == REDIS_REPLY_ARRAY) {
                    for (int j = 0; j < reply->elements; j++) {
                        //printf("%u) %s\n", j, reply->element[j]->str);
                        result.push_back(reply->element[j]->str);
                    }
                }
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::SetString(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "SET %s %s", key.data(), value.data());
            ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::GetString(std::string const&key, std::string&value, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "GET %s", key.data());
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->len > 0)
                {
                  value = reply->str;
                }
            
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::SetInt(std::string const&key, int &number, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "SET %s %d", key.data(), number);
            ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::GetInt(std::string const&key, int &number, int dbName)
{
    bool isSuccess = false;
    bool ret = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "SELECT %d", dbName);
        ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
            reply = (redisReply *)redisCommand(node.c, "GET %s", key.data());
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->len > 0) 
                {
                   number = std::atoi(reply->str);
                }
                freeReplyObject(reply);
            }
        }
        BackConnect(node);
    }
    return ret;
}
bool MyRedisPool::PUBLISH(std::string const& theme,std::string const& content)
{
    bool isSuccess = false;
    RedisNode &node = GetConnect(isSuccess);
    if (isSuccess)
    {
        redisReply *reply = (redisReply *)redisCommand(node.c, "PUBLISH %s %s", theme.data(), content.data());
        bool ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
        }
        BackConnect(node);
        return ret;
    }
    return isSuccess;
}
bool MyRedisPool::SUBSCRIBE(std::string const&theme)
{
    redisContext *c = NULL;
    bool ret = CreateOneConnect(c);
    if (ret)
    {
        redisReply *reply = (redisReply *)redisCommand(c, "SUBSCRIBE %s", theme.data());
        freeReplyObject(reply);
        while (redisGetReply(c,(void**)&reply) == REDIS_OK) {
            // consume message
            ret = GetRedisReply(reply);
            if (ret)
            {
                if (reply->elements>0)
                {
                    for (size_t i = 0; i < reply->elements; i++)
                    {
                        std::cout << reply->element[reply->elements-1]->str << std::endl;
                        break;
                    }
                 
                }
            
                freeReplyObject(reply);
            }
            
        }
        if (c)
        {
            redisFree(c);
        }
    }
    return ret;
}
bool MyRedisPool::BackConnect(RedisNode& node)
{
    std::lock_guard<std::mutex> lck(m_Lock);
    for (size_t i = 0; i < m_RedisVec.size(); i++)
    {
        RedisNode& n = m_RedisVec[i];
        if (node.id == n.id)
        {
            n.isUsed = false;
            break;
        }
    }
    return true;
}
bool MyRedisPool::DisConnect()
{
    std::lock_guard<std::mutex> lck(m_Lock);
    for (size_t i = 0; i < m_RedisVec.size(); i++)
    {
        RedisNode& node = m_RedisVec[i];
        if (node.c)
        {
            redisFree(node.c);
        }
    }
    return true;
}
bool MyRedisPool::AddConnect()
{
    size_t size = m_MaxConnects - m_CurConnects;
    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    for (size_t i = 0; i < size; i++)
    {
        RedisNode node;
#ifdef _WIN32
            node.c = redisConnectWithTimeout(m_Host.data(), m_Port, timeout);
#else
            node.c = redisConnectUnixWithTimeout(hostname, timeout);
#endif
            if (node.c == NULL || node.c->err) {
                if (node.c) {
                    std::lock_guard<std::mutex> lck(m_PrintLock);
                    printf("Connection error: %s\n", node.c->errstr);
                    redisFree(node.c);
                }
                else {
                    std::lock_guard<std::mutex> lck(m_PrintLock);
                    printf("Connection error: can't allocate redis context\n");
                }
                continue;
            }
            if (m_PassWord.length()>0)
            {
                redisReply *reply = (redisReply *)redisCommand(node.c, "AUTH %s ", m_PassWord.data());
                bool ret = GetRedisReply(reply);
                if (ret)
                {
                    freeReplyObject(reply);
                }
                else
                {
                    redisFree(node.c);
                    continue;
                }
            }
            
            if (m_QueueId.size()>0)
            {
                node.id = m_QueueId.front();
                m_QueueId.pop();
            }
            else
            {
                node.id = i;
            }
        
            node.isUsed = false;
            m_RedisVec.push_back(node);
            m_CurConnects++;
    }
    return true;
}
bool MyRedisPool::CreateOneConnect(redisContext *&c)
{
    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
#ifdef _WIN32
    c = redisConnectWithTimeout(m_Host.data(), m_Port, timeout);
#else
    c = redisConnectUnixWithTimeout(hostname, timeout);
#endif
    if (c == NULL || c->err) {
        if (c) {
            printf("Connection error: %s\n", c->errstr);
            redisFree(c);
        }
        else {
            printf("Connection error: can't allocate redis context\n");
        }
        return false;
    }
    if (m_PassWord.length()>0)
    {
        redisReply *reply = (redisReply *)redisCommand(c, "AUTH %s ", m_PassWord.data());
        bool ret = GetRedisReply(reply);
        if (ret)
        {
            freeReplyObject(reply);
        }
        else
        {
            redisFree(c);
            return false;
        }
    }
    return true;
}
RedisNode& MyRedisPool::GetConnect(bool& isSuccess)
{
    std::lock_guard<std::mutex> lck(m_Lock);
    bool used = false;
    isSuccess = false;
    for (size_t i = 0; i<m_RedisVec.size(); i++)
    {
        RedisNode& node = m_RedisVec[i];
        if (!node.isUsed)
        {
            redisReply *reply = (redisReply *)redisCommand(node.c, "PING");
            bool ret = GetRedisReply(reply);
            if (ret)
            {
                std::lock_guard<std::mutex> lck(m_PrintLock);
                printf("PING: %s\n", reply->str);
                freeReplyObject(reply);
                node.isUsed = true;
                isSuccess = true;
                return node;
            }
            else
            {
                redisFree(node.c);
                m_RedisVec.erase(std::begin(m_RedisVec) + i);
            }
            
            
        }
    }
    if (m_RedisVec.size()<=0)
    {
        AddConnect();
        for (size_t i = 0; i < m_RedisVec.size(); i++)
        {
            RedisNode& node = m_RedisVec[i];
            if (!node.isUsed)
            {
                redisReply *reply = (redisReply *)redisCommand(node.c, "PING");
                bool ret = GetRedisReply(reply);
                if (ret)
                {
                    std::lock_guard<std::mutex> lck(m_PrintLock);
                    printf("PING: %s\n", reply->str);
                    freeReplyObject(reply);
                    node.isUsed = true;
                    isSuccess = true;
                    return node;
                }
                else
                {
                    redisFree(node.c);
                    m_RedisVec.erase(std::begin(m_RedisVec) + i);
                }


            }
        }
    }
    return (RedisNode&)isSuccess;
}
bool MyRedisPool::InitConnect(std::string const& host, std::string const& password,int port,int count)
{
    m_RedisVec.clear();
    m_Host = host;
    m_PassWord = password;
    m_Port = port;

    m_MaxConnects = count;
    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    for (size_t i = 0; i < count; i++)
    {
        RedisNode node;
#ifdef _WIN32
        node.c = redisConnectWithTimeout(m_Host.data(), m_Port, timeout);
#else
        node.c = redisConnectUnixWithTimeout(hostname, timeout);
#endif
        if (node.c == NULL || node.c->err) {
            if (node.c) {
                printf("Connection error: %s\n", node.c->errstr);
                redisFree(node.c);
            }
            else {
                printf("Connection error: can't allocate redis context\n");
            }
            return false;
        }
        if (m_PassWord.length()>0)
        {
            redisReply *reply = (redisReply *)redisCommand(node.c, "AUTH %s ", m_PassWord.data());
            bool ret = GetRedisReply(reply);
            if (ret)
            {
                freeReplyObject(reply);
            }
            else
            {
                redisFree(node.c);
                continue;
            }
        }
        node.id = i;
        node.isUsed = false;
        m_RedisVec.push_back(node);
        m_CurConnects++;
        m_QueueId.push(i);
    }
}
MyRedisPool& MyRedisPool::GetInstance()
{
    static MyRedisPool _instance;
    return _instance;
}
#endif // _MY_REDIS_POOL_HPP_
 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值