工作须要对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. BZOJ2179: FFT快速傅立叶 & caioj1450:【快速傅里叶变换】大整数乘法

    [传送门:BZOJ2179&caioj1450] 简要题意: 给出两个超级大的整数,求出a*b 题解: Rose_max出的一道FFT例题,卡掉高精度 = =(没想到BZOJ也有) 只要把a和 ...

  2. System Databases in SQL Server

    https://docs.microsoft.com/en-us/sql/relational-databases/databases/system-databases SQL Server incl ...

  3. tp5自定义扩展类的使用extend

    1.在入口index.php定义目录 define('EXTEND_PATH', __DIR__ .'/../extend/'); 2.在使用页引用 use lib\Page; 3.初始化 $page ...

  4. html5播放m3u8视频,web端看直播

    https://github.com/jiqing9006/hLive <!DOCTYPE html> <html> <head> <meta charset ...

  5. 隐藏tomcat nginx版本信息

    Tomcat --首先备份tomcat .首先找到这个jar包,$TOMCAT_HOME/lib/catalina.jar .解压catalina.jar之后按照路径\org\apache\catal ...

  6. kali 2.0 linux中的Nmap的主机探测

    不多说,直接上干货! 如果是第一次接触Nmap,推荐在MSF终端中输入不加任何参数的Nmap命令,以查看其使用方法. 更多,其实, msf > nmap -h [*] exec: nmap -h ...

  7. zookeeper伪分布安装配置

    1.下载路径为:http://mirrors.cnnic.cn/apache/zookeeper/stable/ 2.安装: 第一步 解压zookeeper压缩包: 进入 zookeeper安装目录 ...

  8. 使用Java操作Redis(二)

    上篇文章中我们可以看到,通过自己动手编码来操作Redis是相当繁琐的,实际上我们在重复制造轮子.Redis网站上列举出了一些方便操作Redis的常用工具. 可供Java选择的比较多,这里介绍一下Jed ...

  9. RadioButton的drawableTop图片文字不居中

    在安卓应用的开发中,一般普通应用用到最多的就是底部放一个RadioGroup实现切换的布局,今天在实现的时候,却出现了底部RadiButton的drawableTop图片及文字无法居中的情况,经过对比 ...

  10. 关于ListView的一些不常用到的属性

    1.setCacheColorHint自定义listview的时候,当你不使用Android:cacheColorHint=“#00000000”会出现下面选中一个空间黑色底色的情况,破坏整体美观度 ...