hiredis c客户端

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值