redis c客户端 hiredis

1.简单介绍

hiredis是一个轻量级的访问redis数据库的c客户端。

它是轻量级的不仅仅是因为它仅仅提供对协议的最小支持,而且它使用了一个高级别的极度类似于printf的api使它的级别远高于其最小代码库和缺乏绑定的redis命令。简而言之,就是更灵活。

除了支持发送命令和接受命令,它还有一个与io层分离的回复解析器。它是一个简单灵活的流解析器,可以用于更高级别的语言绑定以实现有效的回复解析。

 hiredis仅仅支持二进制安全的redsi协议,因此你可以使用它在redis的版本的大于1.2.0.

 hiredis提供多套api,包括同步的api,异步api,回复解析的api.

 

2.同步api

要使用同步api,仅仅需要学会使用几个函数。

redisContext *redisConnect(const char *ip, int port);     
 
void redisFree(redisContext *c);

void *redisCommand(redisContext *c, const char *format, ...);

void freeReplyObject(void *reply);

1)redisConnect返回一个redisContext的结构体, 这个结构用于保存连接状态。这个结构体包含一个integer类型的err数据成员,这个成员非0,当连接处于一个错误状态的时候,另一个string的数据成员指出具体的错误原因。在调用redisConnect之后应该检查err以测试是否连接成功。

2)向redis发送命令有好几种方式。

第一种方式:

redisCommand,提供了一种类似于printf的形式去发送命令。第一个参数是redisConnect的返回值。

最简单的形式:

reply = redisConnect(context, "set foo bar");

使用%s插入字符串的形式:

reply = redisConnect(context, "SET foo %s", value);

发送二进制字符串的形式,但同时需要指出字符串的长度:

reply = redisCommand(context, "SET foo %b",  (szie_t)valuelen);

发送多个分离的字符串的形式:

reply = redisCommand(context, "set key:%s %s", myid, value);

类似于命令行的形式:

void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

第四个参数是每个参数字符串的长度

回复:

当命令成功执行时,redisCommand的返回值会保留一个回复。发生错误时,返回值为NULL,上下文中的err字段将被设置(请参阅错误部分)。一旦错误返回,上下文不能被重用,你应该建立一个新的连接。
标准回复redisCommand的类型是redisReply。 redisReply中的类型字段应该用于测试收到的回复类型:
REDIS_REPLY_STATUS:
该命令回复了状态回复。状态字符串可以使用reply-> str来访问。该字符串的长度可以使用reply-> len来访问。
REDIS_REPLY_ERROR:
该命令回复了一个错误。错误字符串可以与REDIS_REPLY_STATUS相同访问。
REDIS_REPLY_INTEGER:
该命令用一个整数来回答。整数值可以使用long long类型的reply-> integer字段来访问。
REDIS_REPLY_NIL:
该命令回答了一个零对象。没有要访问的数据。
REDIS_REPLY_STRING:
批量(字符串)回复。答复的值可以使用reply-> str来访问。该字符串的长度可以使用reply-> len来访问。
REDIS_REPLY_ARRAY:

多批量回复。多批量答复中的元素数量存储在reply->元素中。多批量回复中的每个元素也是一个redisReply对象,可以通过reply-> element [.. index ..]进行访问。 Redis可能会回应嵌套数组,但这完全受支持。

应使用freeReplyObject()函数释放回复。 请注意,这个函数将负责释放包含在数组和嵌套数组中的子回复对象,所以用户不需要释放子回复(它实际上是有害的并且会损坏内存)。

3)将命令序列化

当redisCommand系列中的任何函数被调用时,Hiredis首先根据Redis协议格式化该命令。然后将格式化的命令放入redisContext的输出缓冲区中。这个输出缓冲区是动态的,所以它可以容纳任意数量的命令。将命令放入输出缓冲区后,调用redisGetReply。这个函数有以下两个执行路径:
        输入缓冲区非空:
            尝试解析来自输入缓冲区的单个回复并将其返回
            如果没有答复可以解析,相当于输入缓冲区为空的情况
        输入缓冲区为空:
            将整个输出缓冲区写入套接字
            从套接字读取,直到可以解析单个回复

对于序列化命令,唯一需要做的事情是填充输出缓冲区。由于这个原因,除了不返回一个回复之外,可以使用两个与redisCommand系列相同的命令,然后我们用redisGetReply获取命令的返回结果。

void redisAppendCommand(redisContext *c, const char *format, ...);

void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

官方文档如上描述,但其实源码中这两个命令的返回值是int。

使用方法如下:

redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);

4)error

当函数调用不成功时,根据函数返回NULL或REDIS_ERRcontext中的err字段将为非零值,并设置为以下常量之一:
REDIS_ERR_IO:创建连接时发生I / O错误,尝试写入套接字或从套接字读取。 如果您在应用程序中包含errno.h,则可以使用全局errno变量来找出错误。
REDIS_ERR_EOF:服务器关闭导致空读的连接。
REDIS_ERR_PROTOCOL:解析协议时发生错误。
REDIS_ERR_OTHER:任何其他错误。 目前,只有在指定的主机名连接时才能使用它。
在任何情况下,context中的errstr字段都将设置为保存错误的字符串表示形式

 

3.代码

编译的时候切记加上动态链接库。可以使用pkg-config --cflags --libs hiredis显示如何加。

#include <stdio.h>
#include <stdlib.h>
#include <hiredis.h>

void prase(redisReply *reply)
{
    int seq = 0;

    if (NULL == reply)
    {
        printf("redisReply id NULL\n");
        return;
    }

    switch (reply->type)
    {
    case REDIS_REPLY_STATUS:
        printf("REDIS_REPLY_STATUS:%s\n", reply->str);
        break;
    case REDIS_REPLY_ERROR:
        printf("REDIS_REPLY_ERROR:%s\n", reply->str);
        break;
    case REDIS_REPLY_INTEGER:
        printf("REDIS_REPLY_INTEGER:%lld\n", reply->integer);
        break;
    case REDIS_REPLY_NIL:
        printf("REDIS_REPLY_NIL:NULL\n");
        break;
    case REDIS_REPLY_STRING:
        printf("REDIS_REPLY_STRING:%s\n", reply->str);
        break;
    case REDIS_REPLY_ARRAY:
        printf("REDIS_REPLY_ARRAY\n");
        while (seq < reply->elements)
        {
            printf("    REDIS_REPLY_STRING:%s   ", reply->element[seq]->str);
            if (seq++ % 3 == 0)
            {
                printf("\n");
            }
        }

        printf("\n");
        break;
    default:
        break;
    }

    freeReplyObject(reply);
}

int main()
{
    redisContext *c = redisConnect("127.0.0.1", 6379);

    if ((c == NULL) || c->err)
    {
        if (c)
        {
            printf("Error:%s\n", c->errstr);
        }
        else
        {
            printf("conn't allocate redis context\n");
        }

        exit(-1);
    }

    printf("redis connect return %d:%s\n", c->err, c->errstr);

    redisReply *reply = (redisReply*)redisCommand(c, "set company noahwm");
    prase(reply);
    reply = (redisReply*)redisCommand(c, "set phone 17621079235");
    prase(reply);
    reply = (redisReply*)redisCommand(c, "keys *");
    prase(reply);

    return 0;
}

修改main函数

int main()
{
    redisContext *c = redisConnect("127.0.0.1", 6379);

    if ((c == NULL) || c->err)
    {
        if (c)
        {
            printf("Error:%s\n", c->errstr);
        }
        else
        {
            printf("conn't allocate redis context\n");
        }

        exit(-1);
    }

    printf("redis connect success\n");
    redisReply *reply = (redisReply*)redisCommand(c, "set company noahwm");
    prase(reply);
    reply = (redisReply*)redisCommand(c, "set phone 17621079235");
    prase(reply);
    redisAppendCommand(c, "set family henan");
    redisGetReply(c, (void**)&reply); // reply for SET                     
    prase(reply);
    reply = (redisReply*)redisCommand(c, "keys *");
    prase(reply);
    return 0;
}

如果使用完append类的command函数之后我们不使用redisGetReply得到回复,那么下一个命令的回复就是上一条命令的回复

密码验证

int main()
{
    c = redisConnect((char*)redis_host, redis_port);
    if (c->err)  /* Error flags, 0 when there is no error */
    {
        printf("连接Redis失败: %s\n", c->errstr);
        exit(1);
    }
    else
    {
        printf("连接Redis成功!\n");
    }

    reply = (redisReply *)redisCommand(c, "AUTH %s", redis_password);
    if (reply->type == REDIS_REPLY_ERROR)
    {
        printf("Redis认证失败!\n");
    }
    else
    {
        printf("Redis认证成功!\n");
    }

    freeReplyObject(reply);
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值