工作须要对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);

以下直接上封装后的代码:

class KGRedisClient
{
public:
KGRedisClient(string ip, int port, int timeout = 2000);
virtual ~KGRedisClient(); bool ExecuteCmd(const char *cmd, size_t len, string &response);
redisReply* ExecuteCmd(const char *cmd, size_t len); private:
int m_timeout;
int m_serverPort;
string m_setverIp;
CCriticalSection m_lock;
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);
}; KGRedisClient::KGRedisClient(string ip, int port, int timeout)
{
m_timeout = timeout;
m_serverPort = port;
m_setverIp = ip; m_beginInvalidTime = 0;
} KGRedisClient::~KGRedisClient()
{
CAutoLock autolock(m_lock);
while(!m_clients.empty())
{
redisContext *ctx = m_clients.front();
redisFree(ctx);
m_clients.pop();
}
} bool KGRedisClient::ExecuteCmd(const char *cmd, size_t len,string &response)
{
redisReply *reply = ExecuteCmd(cmd, len);
if(reply == NULL) return false; boost::shared_ptr<redisReply> autoFree(reply, freeReplyObject);
if(reply->type == REDIS_REPLY_INTEGER)
{
response = _IntToStrA(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 *cmd, size_t len)
{
redisContext *ctx = CreateContext();
if(ctx == NULL) return NULL; redisReply *reply = (redisReply*)redisCommand(ctx, "%b", cmd, len); ReleaseContext(ctx, reply != NULL); return reply;
} redisContext* KGRedisClient::CreateContext()
{
{
CAutoLock autolock(m_lock);
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;
} return ctx;
} void KGRedisClient::ReleaseContext(redisContext *ctx, bool active)
{
if(ctx == NULL) return;
if(!active) {redisFree(ctx); return;} CAutoLock autolock(m_lock);
m_clients.push(ctx);
} bool KGRedisClient::CheckStatus(redisContext *ctx)
{
redisReply *reply = (redisReply*)redisCommand(ctx, "ping");
if(reply == NULL) return false; boost::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);

Redisclient连接方式Hiredis简单封装使用,连接池、屏蔽连接细节的更多相关文章

  1. 快速理解VirtualBox的四种网络连接方式

    VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...

  2. VirtualBox的四种网络连接方式【转】

    VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...

  3. Vmare虚拟机网络连接方式桥接模式+桥接模式+主机模式

    虚拟机网络连接模式 最近在学习虚拟机和计算机网络,在网上看了一些关于虚拟机网络连接方式的介绍 这篇文章写的不错:https://www.cnblogs.com/luxiaodai/p/9947343. ...

  4. oracle多表连接方式Hash Join Nested Loop Join Merge Join

    在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式:        嵌套循环(Nested  Loops (NL) ...

  5. jsp实时显示后台批处理进度 - out分块,简单的长连接方式

    这两天在实现一个批处理操作,但是想让前台实时显示后台批处理进度,本想着用复杂一些的框架可以实现异步信息调用 但是鉴于是内部管理系统,且只有一两个人用到这个功能,所以做了一个简单的长连接方式的实时响应 ...

  6. Dapper连接与事务的简单封装

    增删改查方面,已经有Dapper.Extension这么强大的工具了,我也实在没啥好写的,就随手写了个看起来比较优雅的连接与事务的封装.在之后使用Dapper.Extension类库时,完全可以照搬进 ...

  7. java架构之路-(Redis专题)SpringBoot连接Redis超简单

    上次我们搭建了Redis的主从架构,哨兵架构以及我们的集群架构,但是我们一直还未投入到实战中去,这次我们用jedis和springboot两种方式来操作一下我们的redis 主从架构 如何配置我上次已 ...

  8. Java中数据库连接池原理机制的详细讲解以及项目连接数据库采用JDBC常用的几种连接方式

    连接池的基本工作原理 1.基本概念及原理 由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理.我们知道,对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式 ...

  9. JAVA数据源连接方式汇总

    最近在研究JAVA的数据源连接方式,学习的时候发现了一位同行写的文章,转载过来,留作记录! 一.问题引入 在java程序中,需要访问数据库,做增删改查等相关操作.如何访问数据库,做数据库的相关操作呢? ...

随机推荐

  1. MetaSploit攻击实例讲解------工具Meterpreter常用功能介绍(kali linux 2016.2(rolling))(详细)

    不多说,直接上干货! 说在前面的话 注意啦:Meterpreter的命令非常之多,本篇博客下面给出了所有,大家可以去看看.给出了详细的中文 由于篇幅原因,我只使用如下较常用的命令. 这篇博客,利用下面 ...

  2. Swift学习笔记(1):基础部分

    目录: 分号 常量和变量 数据类型 数值型类型转换 类型别名 元组 可选类型 API版本检查 分号 Swift并不强制要求你在每条语句的结尾处使用分号( ; ),你也可以按照自己的习惯添加分号.如果在 ...

  3. P2264 情书(字符串hash90分)

    题目背景 一封好的情书需要撰写人全身心的投入.lin_toto同学看上了可爱的卡速米想对她表白,但却不知道自己写的情书是否能感动她,现在他带着情书请你来帮助他. 题目描述 为了帮助lin_toto,我 ...

  4. HDU 4324 Triangle LOVE【拓扑排序】

    题意:给出n个人,如果a喜欢b,那么b一定不喜欢a,如果b不喜欢a,那么a一定喜欢b 就是这n个点里面的任意两点都存在一条单向的边, 所以如果这n个点不能构成拓扑序列的话,就一定成环了,成环的话就一定 ...

  5. PL/SQL Developer 关闭Sql窗口快捷键

    preferences->keyconfigration->file/close然后设置你喜欢的按键就行了.(ps:这个close是关闭当前活动的那一个页面)

  6. python的模块导入机制

    在python中用import或者from...import来导入相应的模块. 模块(Module)其实就是一些函数和类的集合文件,它能实现一些相应的功能,当我们需要使用这些功能的时候,直接把相应的模 ...

  7. JavaScript:理解prototype与__proto__,原型与原型链

    JS中的继承是原型继承,通过原型实现的.为了理解原型,我想先讲讲对象的内部属性[[prototype]]和属性__proto__,函数的属性prototype. 对象的内部属性[[prototype] ...

  8. 关联Anaconda和最新Pycharm2018.3.2

    在Anaconda和Pycharm 2018.3.2 x64都安装好之后,进行Anaconda 与Pycharm的关联操作 首先File -->New Project 打开以后切记要把Proje ...

  9. qduoj~前端~二次开发

    青岛大学qdu的onlinejudge是js的写的前端,框架是vue.js,在nodejs上部署运行,其实整体运行还是建立在docker的容器虚拟环境里,这里暂时不需要docker.安装环境是Ubun ...

  10. socket 编程的端口和地址复用

    在linux socket网络编程中,大规模并发TCP或UDP连接时,经常会用到端口复用:   int opt = 1;   if(setsockopt(sockfd, SOL_SOCKET,SO_R ...