hiredis php,redis 连接池 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);

封装后的代码:

redis_pool.h

#ifndef __REDIS_POOL_H__

#define __REDIS_POOL_H__

#include

#include

#include

#include

#include

#include

#include

#include

#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 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

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 <: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 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 <: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 <: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 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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值