The work requires a simple encapsulation of the Hiredis to enable the function:
1, the API is unified, external only provide an interface;
2, the shielding upper layer application to the connection details processing;
3, the bottom of the queue to maintain the connection pool, save the connection session;
4, re-connect the use of time-stamp control, every time (3s) to re-connect once, to prevent frequent retries caused by unnecessary waste.
Let's take a look at Hiredis's common data structures and APIs:
Hiredis/hiredis.h/* Context for a connection to Redis */typedef struct REDISCONTEXT {int err;/* Error flags, 0 W Hen 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; /* 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 R
edisreply {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);
The following directly on the encapsulated code:
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 (); }} BOOLKgredisclient::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 a 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;
}
Slightly explained:
Member variable: m_clients is used to save the connection pool.
Member variables: m_begininvalidtime, m_maxreconnectinterval are used to control frequent connections when they are broken off.
External api:executecmd (const char *cmd, string &response);