Redis客户端连接方式Hiredis简单封装使用,连接池、屏蔽连接细节
2015-03-17 11:12
579 查看
工作需要对Hiredis进行了简单封装,实现功能:
1、API进行统一,对外只提供一个接口;
2、屏蔽上层应用对连接的细节处理;
3、底层采用队列的方式保持连接池,保存连接会话;
4、重连时采用时间戳进行控制,每隔一定时间(3s)重连一次,防止频繁重试造成的不必要浪费。
先看一下Hiredis的常用数据结构与API:
下面直接上封装后的代码:
稍加解释:
成员变量:m_clients用于保存连接池。
成员变量:m_beginInvalidTime、m_maxReconnectInterval 用于控制断掉时的频繁连接。
对外API:ExecuteCmd(const char *cmd, string &response);
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简单封装使用,连接池、屏蔽连接细节
- 使用连接池的方式连接数据库:使用DBUtil连接MYSQL数据库
- winsock简单使用(采用select轮询方式,从客户端获取数据)
- 对iOS网络请求的简单封装,并且使用block回调函数方式
- Redis 客户端Jedis使用---连接池
- Android客户端post方式连接web(servlet)服务器实现简单登录
- redis简单使用及用JSON字符串的方式解决对象存储问题
- 使用Redis的Java客户端Jedis 使用连接池+分布式
- redis学习之Jedis使用线程池封装redis的基本操作及spring的简单封装
- java客户端连接MongoDB数据库的简单使用
- 使用自定义证书并忽略验证的HTTPS连接Post请求方式的封装
- ORACLE dblink数据库连接 使用简单字符串方式
- redis客户端jedis的简单使用
- redis java客户端Jedis 实现 连接池 + 简单的负载均衡
- 在使用 SQL Server 的过程中,用户遇到最多的问题莫过于连接失败了。一般而言,有两种连接SQL Server 的方式,一是利用 SQL Server 自带的客户端工具
- join连接的五种方式的简单使用案例(Inner join,Left join,Right join,Full join,Cross join)
- 在非SQL客户端使用命令行方式定期连接SQL Server 服务器并模拟用户查询操作,同时输出信息内容
- 使用Redis客户端hiredis遇到的一些问题
- nodejs连接redis数据库简单封装-redis模块
- Android 使用Socket实现服务器与手机客户端的长连接六:二次封装