1.hiredis 同步客户端
//hiredis获取结果的处理函数数组结构体
typedef struct ReplyHandleFunc
{
ReplyRet (*string_handle_func)(size_t, char*);
ReplyRet (*array_handle_func)(size_t, struct redisReply**);
ReplyRet (*integer_handle_func)(long long);
ReplyRet (*nil_handle_func)();
ReplyRet (*status_handle_func)(size_t, char*);
ReplyRet (*err_handle_func)(size_t, char*);
} ReplyHandleFunc;
//全局获取结果的处理函数数组结构体 这里设计到redis返回结果的五中类型,在之前的博客有讲到
static ReplyHandleFunc replyHandleFunc = {
string_handle,
array_handle,
integer_handle,
nil_handle,
status_handle,
err_handle
};
ReplyRet string_handle(size_t len, char *str){
//服务器返回string,可以实现对string的具体操作,这里是简单的打印
printf("get string : %s\n", str);
return CMD_RET_STR;
}
ReplyRet array_handle(size_t len, struct redisReply** reply){
//服务器返回ARRAY,这里可以实现对ARRAY的具体操作
return CMD_RET_ARRAY;
}
ReplyRet integer_handle(long long number){
//这里可以实现对number的具体操作 这里是简单的打印
printf("get number is %lld\n", number);
return CMD_RET_NUM;
}
ReplyRet nil_handle(void){
//这里返回空,可以进行相应的处理
return CMD_RET_NIL;
}
ReplyRet status_handle(size_t len, char *str){
if(strcmp(str,"OK") == 0)
{
printf("request : %s, message len is %d\n", str, len);
return CMD_RET_OK;
}
return CMD_RET_ERR;
}
ReplyRet err_handle(size_t len, char *str)
{
printf("request err:%s, message len:%d\n", str, len);
return CMD_RET_ERR;
}
//连接redis客户端(hiredis 有几种连接方式,可根据具体情况自行选择,这里选择redisConnectWithTimeout连接方式)
redisContext* hiredis_connect(const char* ip, int port, const struct timeval tv){
redisContext *conn = redisConnectWithTimeout(ip, port, tv);
if(conn != NULL){
if(conn->err){
printf("redisConnectWithTimeout failed cause by %s,errsno:%d\n", conn->errstr,conn->err);
redisFree(conn);
return NULL;
}
}else{
return NULL;
}
return conn;
}
//hiredis 获取返回结果的处理
ReplyRet reply_handle_func(redisReply *reply, ReplyHandleFunc *replyFunc){
ReplyRet ret = CMD_RET_ERR;
switch(reply->type){
case REDIS_REPLY_STRING:
ret = replyFunc->string_handle_func(reply->len, reply->str);
break;
case REDIS_REPLY_ARRAY:
ret = replyFunc->array_handle_func(reply->elements, reply->element);
break;
case REDIS_REPLY_INTEGER:
ret = replyFunc->integer_handle_func(reply->integer);
break;
case REDIS_REPLY_NIL:
ret = replyFunc->nil_handle_func();
break;
case REDIS_REPLY_STATUS:
ret = replyFunc->status_handle_func(reply->len, reply->str);
break;
case REDIS_REPLY_ERROR:
ret = replyFunc->err_handle_func(reply->len, reply->str);
break;
}
return ret;
}
HiredisRet redis_command(redisContext *conn, char *cmd, ReplyHandleFunc *replyFunc)
{
redisReply *reply = (redisReply*)redisCommand(conn, cmd);
if(reply_handle_func(reply, replyFunc) == CMD_RET_ERR)
{
printf("reply_handle_func err\n");
freeReplyObject(reply);
return RET_FAIL;
}
freeReplyObject(reply);
return RET_SUCC;
}
HiredisRet redis_append_command(redisContext *conn, char **cmd, int cmdNum, ReplyHandleFunc *replyFunc)
{
redisReply *reply = NULL;
int ret, i;
for(i = 0; i < cmdNum; i++)
{
ret = redisAppendCommand(conn,cmd[i]);
if(ret < 0)
{
return RET_FAIL;
}
}
for(i = 0; i < cmdNum; i++)
{
ret = redisGetReply(conn, (void**)&reply);
if(ret < 0)
{
freeReplyObject(reply);
return RET_FAIL;
}
reply_handle_func(reply, replyFunc);
}
freeReplyObject(reply);
return RET_SUCC;
}
//函数主入口
int main(int argc, char** argv)
{
int timeout = 10000;
struct timeval tv = {1, 500000};
redisContext *conn = hiredis_connect(IP, PORT, tv);
if(conn){
printf("Connect server success\n");
}else{
printf("Connect server fail\n");
exit(1);
}
const char *buf[3] = {"get friend", "get name", "get foo"};
redis_append_command(conn, buf, 3, &replyHandleFunc);
redisFree(conn);
return 0;
}
以上使用了redisCommand和redisAppendCommand两种方式,前者是分条指令发送,后者会将指令存放于本地的缓冲区,直到redisGetReply后,会批量发送,再逐一将结果返回,因此效率上会比前者快些。理论上应该是这样,没有亲测。当然hiredis也有事件回调的模式,效率应该比这两个再快些,打算在后面的博客也记录一下hiredis事件回调模式。
在这里要记录一下redisAppendCommandArgv这个函数的使用,之前一直没有弄明白它的使用,在网上几乎没有讲到这个函数的使用,后来在github上请教了hiredis的维护者,他们给了我答案,这是michael-grunder的答案,具体的希捷可看https://github.com/redis/hiredis/issues/483。在这里也分享以下:
int main(void) {
int i;
const char *buf[3][2] = {
{"get", "friend"},
{"get", "name"},
{"get", "foo"}
};
char *result;
redisContext *c = redisConnect("127.0.0.1", 6379);
/* Append each GET command */
for (i = 0; i < 3; i++) {
redisAppendCommandArgv(c, 2, buf[i], NULL);
}
redisReply *r;
/* Read them back and display */
for (i = 0; i < 3; i++) {
if (redisGetReply(c, (void**)&r) != REDIS_OK) {
printf("Error getting reply\n");
return -1;
}
if (r->type == REDIS_REPLY_STRING) {
printf("[%s] => %s\n", buf[i][1], r->str);
} else {
printf("Key '%s' not found or isn't a string\n", buf[i][1]);
}
freeReplyObject(r);
}
return 0;
}
最后贴上全部的代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<hiredis.h>
#define IP "127.0.0.1"
#define PORT 6379
typedef enum HiredisRet
{
RET_FAIL,
RET_SUCC,
} HiredisRet;
typedef enum ReplyRet
{
CMD_RET_OK,
CMD_RET_ERR,
CMD_RET_NIL,
CMD_RET_NUM,
CMD_RET_ARRAY,
CMD_RET_STR,
} ReplyRet;
ReplyRet string_handle(size_t len, char *str)
{
//这里可以实现对string的具体操作
printf("get string : %s\n", str);
return CMD_RET_STR;
}
ReplyRet array_handle(size_t len, struct redisReply** reply)
{
//这里可以实现对数组的具体操作
return CMD_RET_ARRAY;
}
ReplyRet integer_handle(long long number)
{
//这里可以实现对number的具体操作
printf("get number is %lld\n", number);
return CMD_RET_NUM;
}
ReplyRet nil_handle(void)
{
return CMD_RET_NIL;
}
ReplyRet status_handle(size_t len, char *str)
{
if(strcmp(str,"OK") == 0)
{
printf("request : %s, message len is %d\n", str, len);
return CMD_RET_OK;
}
return CMD_RET_ERR;
}
ReplyRet err_handle(size_t len, char *str)
{
printf("request err:%s, message len:%d\n", str, len);
return CMD_RET_ERR;
}
typedef struct ReplyHandleFunc
{
ReplyRet (*string_handle_func)(size_t, char*);
ReplyRet (*array_handle_func)(size_t, struct redisReply**);
ReplyRet (*integer_handle_func)(long long);
ReplyRet (*nil_handle_func)();
ReplyRet (*status_handle_func)(size_t, char*);
ReplyRet (*err_handle_func)(size_t, char*);
} ReplyHandleFunc;
static ReplyHandleFunc replyHandleFunc= {
string_handle,
array_handle,
integer_handle,
nil_handle,
status_handle,
err_handle
};
redisContext* hiredis_connect(const char* ip, int port, const struct timeval tv)
{
redisContext *conn = redisConnectWithTimeout(ip, port, tv);
if(conn != NULL)
{
if(conn->err)
{
printf("redisConnectWithTimeout failed cause by %s,errsno:%d\n", conn->errstr,conn->err);
redisFree(conn);
return NULL;
}
}
else
{
return NULL;
}
return conn;
}
ReplyRet reply_handle_func(redisReply *reply, ReplyHandleFunc *replyFunc)
{
ReplyRet ret = CMD_RET_ERR;
switch(reply->type)
{
case REDIS_REPLY_STRING:
ret = replyFunc->string_handle_func(reply->len, reply->str);
break;
case REDIS_REPLY_ARRAY:
ret = replyFunc->array_handle_func(reply->elements, reply->element);
break;
case REDIS_REPLY_INTEGER:
ret = replyFunc->integer_handle_func(reply->integer);
break;
case REDIS_REPLY_NIL:
ret = replyFunc->nil_handle_func();
break;
case REDIS_REPLY_STATUS:
ret = replyFunc->status_handle_func(reply->len, reply->str);
break;
case REDIS_REPLY_ERROR:
ret = replyFunc->err_handle_func(reply->len, reply->str);
break;
}
return ret;
}
HiredisRet redis_command(redisContext *conn, char *cmd, ReplyHandleFunc *replyFunc)
{
redisReply *reply = (redisReply*)redisCommand(conn, cmd);
if(reply_handle_func(reply, replyFunc) == CMD_RET_ERR)
{
printf("reply_handle_func err\n");
freeReplyObject(reply);
return RET_FAIL;
}
freeReplyObject(reply);
return RET_SUCC;
}
HiredisRet redis_append_command(redisContext *conn, char **cmd, int cmdNum, ReplyHandleFunc *replyFunc)
{
redisReply *reply = NULL;
int ret, i;
for(i = 0; i < cmdNum; i++)
{
ret = redisAppendCommand(conn,cmd[i]);
if(ret < 0)
{
return RET_FAIL;
}
}
for(i = 0; i < cmdNum; i++)
{
ret = redisGetReply(conn, (void**)&reply);
if(ret < 0)
{
freeReplyObject(reply);
return RET_FAIL;
}
reply_handle_func(reply, replyFunc);
}
freeReplyObject(reply);
return RET_SUCC;
}
int main(int argc, char** argv)
{
int timeout = 10000;
struct timeval tv = {1, 500000};
redisContext *conn = hiredis_connect(IP, PORT, tv);
if(conn){
printf("Connect server success\n");
}else{
printf("Connect server fail\n");
exit(1);
}
const char *buf[3] = {"get friend", "get name", "get foo"};
redis_append_command(conn, buf, 3, &replyHandleFunc);
redisFree(conn);
return 0;
}