对Hiredis进行了简单封装

1、API进行统一,对外只提供一个接口;

2、屏蔽上层应用对连接的细节处理;

3、底层采用队列的方式保持连接池,保存连接会话;

4、重连时采用时间戳进行控制,每隔一定时间(3s)重连一次,防止频繁重试造成的不必要浪费。

先看一下Hiredis的常用数据结构与API:

//hiredis/hiredis.h
/* Context for a connection to Redis */
typedef struct redisContext {
    int err; /* Error flags, 0 when there is no error */
    char errstr[128]; /* String representation of error when applicable */
    int fd;
    int flags;
    char *obuf; /* Write buffer */
    redisReader *reader; /* Protocol reader */
} redisContext;
/* This is the reply object returned by redisCommand() */
#define REDIS_REPLY_STRING 1
#define REDIS_REPLY_ARRAY 2
#define REDIS_REPLY_INTEGER 3
#define REDIS_REPLY_NIL 4
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6
typedef struct redisReply {
    int type; /* REDIS_REPLY_* */
    long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
    int len; /* Length of string */
    char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
    size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
    struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv);
void redisFree(redisContext *c);

封装后的代码:

redis_pool.h

#ifndef __REDIS_POOL_H__
#define __REDIS_POOL_H__
#include <iostream>
#include <string.h>
#include <string>
#include <stdio.h>
#include <memory>
#include <mutex>
#include <queue>
#include <sys/time.h>
#include "hiredis/hiredis.h"
class KGRedisClient
{
public:
    KGRedisClient(std::string ip, int port, std::string password, int timeout = 2000);
    virtual ~KGRedisClient();
 //   bool ExecuteCmd_spop(const char *cmd, size_t len, std::string &response);
  bool ExecuteCmd_spop(std::string &response, const char* format, ...);
 
 //   redisReply* ExecuteCmd(const char *cmd, size_t len);
     redisReply* ExecuteCmd(const char* format, ...);
private:
    int m_timeout;
    int m_serverPort;
    std::string m_setverIp;
 std::string m_password;
 //   CCriticalSection m_lock;
  std::mutex _mutex;
    std::queue<redisContext *> m_clients;
    time_t m_beginInvalidTime;
    static const int m_maxReconnectInterval = 3;
    redisContext* CreateContext();
    void ReleaseContext(redisContext *ctx, bool active);
    bool CheckStatus(redisContext *ctx);
};
#endif
 
 
redis_pool.cpp
 
#include "redis_pool.h"
#include <stdio.h>
KGRedisClient::KGRedisClient(std::string ip, int port, std::string password, int timeout)
{
    m_timeout = timeout;
    m_serverPort = port;
    m_setverIp = ip;
 m_password = password;
    m_beginInvalidTime = 0;
}
KGRedisClient::~KGRedisClient()
{
//    CAutoLock autolock(m_lock);
 std::unique_lock <std::mutex> lck(_mutex);
    while(!m_clients.empty())
    {
        redisContext *ctx = m_clients.front();
        redisFree(ctx);
        m_clients.pop();
    }
}
bool KGRedisClient::ExecuteCmd(std::string &response, const char* format, ...)
{
 va_list args;
 va_start(args, format);
 redisReply *reply = ExecuteCmd(format, args);
 va_end(args);
   
  if(reply == NULL) return false;
    std::shared_ptr<redisReply> autoFree(reply, freeReplyObject);
    if(reply->type == REDIS_REPLY_INTEGER)
    {
        response = std::to_string(reply->integer);
        return true;
    }
    else if(reply->type == REDIS_REPLY_STRING)
    {
        response.assign(reply->str, reply->len);
        return true;
    }
    else if(reply->type == REDIS_REPLY_STATUS)
    {
        response.assign(reply->str, reply->len);
        return true;
    }
    else if(reply->type == REDIS_REPLY_NIL)
    {
        response = "";
        return true;
    }
    else if(reply->type == REDIS_REPLY_ERROR)
    {
        response.assign(reply->str, reply->len);
        return false;
    }
    else if(reply->type == REDIS_REPLY_ARRAY)
    {
        response = "Not Support Array Result!!!";
        return false;
    }
    else
    {
        response = "Undefine Reply Type";
        return false;
    }
}
redisReply* KGRedisClient::ExecuteCmd(const char* format, ...)
{
 va_list args;
 va_start(args, format);
 
 
    redisContext *ctx = CreateContext();
    if(ctx == NULL) return NULL;
  //  redisReply *reply = (redisReply*)redisCommand(ctx, "spop %b", cmd, len);
 //   redisReply *reply = (redisReply*)redisCommand(ctx, "%s", cmd); 
  redisReply* reply = (redisReply*)redisCommand(ctx, format, args);
   va_end(args);
 
    ReleaseContext(ctx, reply != NULL);
    return reply;
}
 
redisContext* KGRedisClient::CreateContext()
{
    {
//        CAutoLock autolock(m_lock);
  std::unique_lock <std::mutex> lck(_mutex);
        if(!m_clients.empty())
        {
            redisContext *ctx = m_clients.front();
            m_clients.pop();
            return ctx;
        }
    }
    time_t now = time(NULL);
    if(now < m_beginInvalidTime + m_maxReconnectInterval) return NULL;
    struct timeval tv;
    tv.tv_sec = m_timeout / 1000;
    tv.tv_usec = (m_timeout % 1000) * 1000;;
    redisContext *ctx = redisConnectWithTimeout(m_setverIp.c_str(), m_serverPort, tv);
    if(ctx == NULL || ctx->err != 0)
    {
        if(ctx != NULL) redisFree(ctx);
        m_beginInvalidTime = time(NULL);
       
        return NULL;
    }
 redisReply *reply;
 std::string strReply = "AUTH ";
 strReply += m_password;
 reply = (redisReply*)redisCommand(ctx, strReply.c_str());
 freeReplyObject(reply);
 reply = NULL;
 printf("connect OK\n");
    return ctx;
}
void KGRedisClient::ReleaseContext(redisContext *ctx, bool active)
{
    if(ctx == NULL) return;
    if(!active) {redisFree(ctx); return;}
//    CAutoLock autolock(m_lock);
 std::unique_lock <std::mutex> lck(_mutex);
    m_clients.push(ctx);
}
bool KGRedisClient::CheckStatus(redisContext *ctx)
{
    redisReply *reply = (redisReply*)redisCommand(ctx, "ping");
    if(reply == NULL) return false;
    std::shared_ptr<redisReply> autoFree(reply, freeReplyObject);
    if(reply->type != REDIS_REPLY_STATUS) return false;
    if(strcasecmp(reply->str,"PONG") != 0) return false;
    return true;
}

成员变量:m_clients用于保存连接池。

成员变量:m_beginInvalidTime、m_maxReconnectInterval 用于控制断掉时的频繁连接。

对外API:ExecuteCmd(const char *cmd, string &response);

redis 连接池 hiredis的更多相关文章

  1. Redis 连接池的问题

      目录 Redis 连接池的问题    1 1.    前言    1 2.解决方法    1     前言 问题描述:Redis跑了一段时间之后,出现了以下异常. Redis Timeout ex ...

  2. 红眼技术博客 » redis连接池红眼技术博客 » redis连接池

    红眼技术博客 » redis连接池 redis连接池

  3. redis连接池操作

    /** * @类描述 redis 工具 * @功能名 POJO * @author zxf * @date 2014年11月25日 */public final class RedisUtil { p ...

  4. java操作redis redis连接池

    redis作为缓存型数据库,越来越受到大家的欢迎,这里简单介绍一下java如何操作redis. 1.java连接redis java通过需要jedis的jar包获取Jedis连接. jedis-2.8 ...

  5. 三:Redis连接池、JedisPool详解、Redisi分布式

    单机模式: package com.ljq.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; ...

  6. 压测过程中,获取不到redis连接池,发现redis连接数高

    说明:图片截得比较大,浏览器放大倍数看即可(涉及到隐私,打了码,请见谅,如果有疑问,欢迎骚扰). 最近在压测过程中,出现获取不到redis连接池的问题 xshell连接redis服务器,查看连接数,发 ...

  7. Redis连接池

    package com.lee.utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; impor ...

  8. Redis】Java中使用Jedis操作Redis(Maven导入包)、创建Redis连接池

    如果我们使用Java操作Redis, 需要确保已经安装了 redis 服务及 Java redis 驱动. Maven项目可以直接在pom.xml中加入jedis包驱动: <!-- https: ...

  9. redis连接池 jedis-2.9.0.jar+commons-pool2-2.4.2.jar

    java使用Redis连接池  jar包为 jedis-2.9.0.jar+commons-pool2-2.4.2.jar jar下载地址 package com.test; import redis ...

随机推荐

  1. C#学习-构造函数

    如果没有为类显式地定义一个构造函数,则C#编译器会自动生成一个函数体为空的默认无参的实例构造函数. 构造函数主要用于创建类的实例对象. 当调用构造函数创建一个对象时,构造函数会为对象分配内存空间,并初 ...

  2. Git坑换行符自动转换 [转载]

    转自https://www.cnblogs.com/zjoch/p/5400251.html 源起 一直想在 GitHub 上发布项目.参与项目,但 Git 这货比较难学啊.买了一本<Git 权 ...

  3. MySQL Windows 下的安装

    my.ini ####################配置文件开始################### # For advice on how to change settings please s ...

  4. [转] Node.js使用MongoDB3.4+Access control is not enabled for the database解决方案

    今天使用MongoDB时遇到了一些问题 建立数据库连接时出现了warnings 出现这个警告的原因是新版本的MongDB为了让我们创建一个安全的数据库 必须要进行验证 后来在外网找到了答案 解决方案如 ...

  5. es6 let和const

    一.let 1.let块作用域 if(true){ var a=1; let b=2; } console.log("a:"+a);//a:1 console.log(" ...

  6. mysql中cast() 和convert()的用法讲解

    一.在mysql操作中我们经常需要对数据进行类型转换.此时我们应该使用的是cast()或convert(). 二.两者的对比 相同点:都是进行数据类型转换,实现的功能基本等同 不同点:两者的语法不同, ...

  7. 洛谷---小L和小K的NOIP考后放松赛

    链接: https://www.luogu.org/contestnew/show/11805?tdsourcetag=s_pcqq_aiomsg 题解: 没人过的题我就没看 t2: 考虑每个点是朋友 ...

  8. 【转】WPF中的窗口的生命周期

    原文地址:http://www.cnblogs.com/Jennifer/articles/1997763.html WPF中的窗口的生命周期 WPF中所有窗口的基类型都是System.Windows ...

  9. jenkins+ant配置自动化任务全过程

      UI自动化测试(17)  版权声明:本文为博主原创文章,未经博主允许不得转载. 1.首先,你需要写UI自动化测试,本地运行无误 2.利用ant将刚写好的程序运行起来,在Eclipse里边只需要ec ...

  10. 查看windows电脑CPU核心数,线程数

    在Windows中,在cmd命令中输入“wmic”,然后在出现的新窗口中输入“cpu get *”即可查看物理CPU数.CPU核心数.线程数.其中,  Name:表示物理CPU数  NumberOfC ...