Redisclient连接方式Hiredis简单封装使用,连接池、屏蔽连接细节
工作须要对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简单封装使用,连接池、屏蔽连接细节的更多相关文章
- 快速理解VirtualBox的四种网络连接方式
VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...
- VirtualBox的四种网络连接方式【转】
VirtualBox中有4中网络连接方式: NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种,其实他跟VMWare 的网络连接方式都是 ...
- Vmare虚拟机网络连接方式桥接模式+桥接模式+主机模式
虚拟机网络连接模式 最近在学习虚拟机和计算机网络,在网上看了一些关于虚拟机网络连接方式的介绍 这篇文章写的不错:https://www.cnblogs.com/luxiaodai/p/9947343. ...
- oracle多表连接方式Hash Join Nested Loop Join Merge Join
在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式: 嵌套循环(Nested Loops (NL) ...
- jsp实时显示后台批处理进度 - out分块,简单的长连接方式
这两天在实现一个批处理操作,但是想让前台实时显示后台批处理进度,本想着用复杂一些的框架可以实现异步信息调用 但是鉴于是内部管理系统,且只有一两个人用到这个功能,所以做了一个简单的长连接方式的实时响应 ...
- Dapper连接与事务的简单封装
增删改查方面,已经有Dapper.Extension这么强大的工具了,我也实在没啥好写的,就随手写了个看起来比较优雅的连接与事务的封装.在之后使用Dapper.Extension类库时,完全可以照搬进 ...
- java架构之路-(Redis专题)SpringBoot连接Redis超简单
上次我们搭建了Redis的主从架构,哨兵架构以及我们的集群架构,但是我们一直还未投入到实战中去,这次我们用jedis和springboot两种方式来操作一下我们的redis 主从架构 如何配置我上次已 ...
- Java中数据库连接池原理机制的详细讲解以及项目连接数据库采用JDBC常用的几种连接方式
连接池的基本工作原理 1.基本概念及原理 由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理.我们知道,对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式 ...
- JAVA数据源连接方式汇总
最近在研究JAVA的数据源连接方式,学习的时候发现了一位同行写的文章,转载过来,留作记录! 一.问题引入 在java程序中,需要访问数据库,做增删改查等相关操作.如何访问数据库,做数据库的相关操作呢? ...
随机推荐
- C# 蚁群优化算法实现
C# 蚁群优化算法实现 需求为(自己编的,非实际项目): 某配送中心进行揽货,目标客户数为50个客户,配送中心目前的运力资源如下: 现有车辆5台 单台运力最大行驶距离200千米 单台运力最大载重公斤1 ...
- 46. AngularJS所有版本下载
转自:https://www.cnblogs.com/best/tag/Angular/ 官网下载:https://angularjs.org/ AngularJS所有版本下载:https://cod ...
- 用jquery给select加选中事件
select在前端开发过程中很常用,现在我们要实现一个效果,那就是选中select中的某一项,执行事件,本来自己没怎么接触过这些,最后网上找了一些资料,自己研究了一下,把方法分享给大家,大家如果有需要 ...
- php7-swoole-Class 'swoole_websocket_server' not found 问题
标签(空格分隔): php 分析 nginx/apache 读取的php.uini 文件 和 cli模式的php.ini 文件不同导致的 swoole是在cli模式下运行的 或许你安装swoole扩展 ...
- 索引-mysql索引创建、查看、删除及使用示例
mysql索引创建.查看.删除及使用示例 1.创建索引: ALTER TABLE用来创建普通索引.UNIQUE索引或PRIMARY KEY索引. ALTER TABLE table_name ADD ...
- Bayes++ Library入门学习之熟悉UKF相关类
UKF-SLAM是一种比较流行SLAM方案.相比EKF-SLAM,UKF利用unscented transform代替了EKF的线性化趋近,因而具有更高的精度.Bayes++库中的unsFlt.hpp ...
- RSA不对称加密
package sinRsa; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io ...
- MFC打包生成可安装文件
一.问题来源: VS环境:编写的MFC程序即使静态联编之后,在客户机器上还是打不开.可能的原因是你开发的时候调用了第三方ActiveX控件.这时候就需要把自己的release版的发布软件和*.ocx控 ...
- 「BZOJ3343」教主的魔法(分块+二分查找)
题意: 给定一个数列,您需要支持以下两种操作:给[l,r]同加一个数询问[l,r]中有多少数字大于或等于v (n<=1000000,m<=3000) 题解 块内排序二分查询修改就用个数组存 ...
- nginx配置aliyun https
server { listen 443; server_name www.goforit.com goforit.com; ssl on; ssl_certificate cert/goforit.p ...