精华内容
下载资源
问答
  • Hiredis

    千次阅读 2017-11-29 14:49:03
    简介本文翻译自Hiredis官方,README.md文件。Hiredis是Redis数据库的简约C客户端库。它是简约的,因为它只是增加了对协议的 最小支持,但是同时它使用了一个高级别的printf-like API,所以对于习 惯了printf风格的...

    简介

    本文翻译自Hiredis官方,README.md文件。

    Hiredis是Redis数据库的简约C客户端库。它是简约的,因为它只是增加了对协议的
    最小支持,但是同时它使用了一个高级别的printf-like API,所以对于习
    惯了printf风格的C编程用户来说,其非常容易使用,而且API中没有明确的绑定 每
    个Redis命令。

    除了支持发送命令和接收回复之外,它还附带了一个与I / O层分离的回复解析器。
    为了方便复用,其设计成为一个流解析器,例如可以在更高级别的语言
    绑定中使用,以实现高效的回复解析。

    Hiredis仅支持二进制安全(binary-safe)的Redis协议,因此您可以将其与任何
    Redis版本(> = 1.2.0)配合使用。

    该库带有多个API。 有同步API,异步API和答复解析API。

    Synchronous API

    要使用SynchronousAPI,只需要引入几个函数调用:

    redisContext *redisConnect(const char *ip, int port);
    void *redisCommand(redisContext *c, const char *format, ...);
    void freeReplyObject(void *reply);

    Connecting

    函数redisConnect用于创建所谓的redisContext结构。redisContext
    Hiredis持有连接状态的地方。当连接处于错误状态时,redisContext结构的整
    err字段不为零。errstr字段将包含一个描述错误的字符串。 有关错误的更多
    信息可以在Errors部分找到。 尝试使用redisConnect连接到Redis后,应检
    err字段以查看建立连接是否成功:

    redisContext *c = redisConnect("127.0.0.1", 6379);
    if (c == NULL || c->err) {
        if (c) {
            printf("Error: %s\n", c->errstr);
            // handle error
        } else {
            printf("Can't allocate redis context\n");
        }
    
    }

    注意:一个redisContext结构是线程非安全的。

    Sending commands

    有几种方法可以向Redis发出命令。 首先介绍的是redisCommand。 这个函数
    的格式类似于printf。 最简单的形式是这样使用的:

    reply = redisCommand(context, "SET foo bar");

    说明符%s在命令中插入一个字符串,并使用strlen来确定字符串的长度:

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

    当您需要在命令中传递二进制安全字符串时,可以使用%b说明符。 与指向字符
    串的指针一起,它需要字符串的size_t长度参数:

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

    在内部,Hiredis将命令拆分为不同的参数,并将其转换为与Redis进行通信的
    协议。 一个或多个空格分隔参数,因此您可以在参数的任何位置使用说明符:

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

    Using replies

    当命令成功执行时,redisCommand的返回值保留一个回复。 发生错误时,返回
    值为NULL,上下文中的err字段将被设置(请参阅Errors部分)。 **一旦错
    误返回,上下文不能被重用,你应该建立一个新的连接。**

    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

      • 该命令回答了一个无效的nil对象。 其表示没有数据可以访问。
    • REDIS_REPLY_STRING:

      • 批量数据(字符串)回复。 答复的值可以使用reply-> str来访问。 这个字
        符串的长度可以使用reply-> len来访问。
    • REDIS_REPLY_ARRAY:

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

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

    **重要提示:hiredis(0.10.0)版本在使用异步API时会主动释放回复对象。
    这意味着当你使用这个API时你不应该调用freeReplyObject。 在回调返回之后,回
    复对象被hiredis清除。 这种行为在未来的版本中可能会发生变化,因此请务必在升
    级时密切关注更新日志(请参阅问题#39)。**

    Cleaning up

    要断开和释放上下文,可以使用以下功能:

    void redisFree(redisContext *c);

    这个函数立即关闭套接字,然后释放创建上下文的分配。

    Sending commands (cont’d)

    redisCommand功能类似一起,函数redisCommandArgv也可用于发出命
    令。 它有以下原型:

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

    它需要参数的数量argc,一个字符串数组argv和参数数组argv的长度。 为了方
    便,argvlen可以设置为NULL,函数将在每个参数上使用strlen来确定它的
    长度。 显然,当任何参数需要binary-safe时,应提供整个参数数组的长度。

    返回值与redisCommand具有相同的语义。

    Pipelining

    为了解释Hiredis如何支持阻塞连接中的流水线,需要了解内部执行流程。

    redisCommand系列中的任何函数被调用时,Hiredis首先根据Redis协议格
    式化命令,格式化的命令然后被放入输出缓冲区下, 这个输出缓冲区是动态的,所以它
    可以容纳任意数量的命令。将命令放入输出缓冲区后,然后调用
    redisGetReply。 这个函数遵循两个执行路径:

    1. 输出缓冲区非空:
      • 尝试解析来自输入缓冲区的单个回复并将其返回
      • 如果没有答复可以解析,请继续2
    2. 输出缓冲区为空:
      • 将整个输出缓冲区写入套接字
      • 从套接字等待读取,直到可以解析一个单一的答复

    函数redisGetReply作为Hiredis 的数据导出API,可以在用于套接字上等待预期回
    复的场景。
    对于管道命令,唯一需要做的事情是填充输出缓冲区。 为了实现这个功能,可以使
    用两个与redisCommand类似的命令,但它们不返回一个回复:

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

    在调用一个或多个上述函数之后,redis Get Reply可以用来接收随后的答复。这
    个函数的返回值是REDIS_OKREDIS_ERR,其中后者意味着在处理答复时发
    生错误。 正如其他命令一样,上下文中的“err”字段可用于找出导致此错误的原因。

    下面的例子显示了一个简单的流水线(导致一次调用write(2)和一次调用read
    (2)
    ):

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

    This API can also be used to implement a blocking subscriber:

    reply = redisCommand(context,"SUBSCRIBE foo");
    freeReplyObject(reply);
    while(redisGetReply(context,&reply) == REDIS_OK) {
        // consume message
        freeReplyObject(reply);
    }

    这个API也可以用来实现阻塞的用户订阅:

    reply = redisCommand(context,"SUBSCRIBE foo");
    freeReplyObject(reply);
    while(redisGetReply(context,&reply) == REDIS_OK) {
        // consume message
        freeReplyObject(reply);
    }

    Errors

    当一个函数调用不成功时,根据函数返回值为“NULL”或“REDIS_ERR”。 上下文中
    的“err”字段将不为零,并设置为其中的一个以下常量:

    • REDIS_ERR_IO
      创建连接时其试图写入到套接字或从套接字读取数据,但该操作出现I/O了错误。
      如果你包了errno.h在你的应用程序中,你可以使用全局的errno变量来找出是
      什么错误。

    • REDIS_ERR_EOF
      服务器关闭导致一次空的读取。

    • REDIS_ERR_PROTOCOL
      解析Redis协议时出现问题。

    • REDIS_ERR_OTHER
      其他类型的错误。目前,其仅使用于指定的主机地址无法解析的情况下。

    在任何情况下,上下文中的errstr字段将被设置为保存字符串形式的错误提示。

    Asynchronous API

    Hiredis提供了一个异步API,可以轻松地与任何事件库一起工作。可以参考Hiredis
    使用的事件库为: libev或[libevent]
    (http://monkey.org/~provos/libevent/).

    Connecting

    函数redisAsyncConnect可以用来建立一个与Redis的非阻塞连接。它返回一个指
    向新创建的redisAsyncContext结构的指针。err字段应在创建后检查,看看是
    否有错误的创建连接。**由于要创建的连接是非阻塞的,因此如果指定的主机
    和端口能够接受连接,内核将无法立即返回。**

    注意:一个redisAsyncContext是非线程安全的

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("Error: %s\n", c->errstr);
        // handle error
    }

    redisAsyncContext可以保存链接异常处理回调函数,用于处理链接断开时的事
    务(可能由于链接错误或是用户主动要求断开链接)。回调函数的原型如下:

    void(const redisAsyncContext *c, int status);

    在断开连接时,当用户主动断开连接时status参数被设置为REDIS_OK,当断线
    是由错误引起时,status参数被设置为REDIS_ERR。当它是REDIS_ERR时,
    可以访redisAsyncContext中的err字段来找出错误的原因。断开连接回调
    后,redisAsyncContext总是被释放。 当需要重新连接时,上述的回调函数是一个
    很好的选择。

    一个redisAsyncContext只能被设置一次处理链接断开的回调函数,其重复设置
    将导致REDIS_ERR。设置回调函数的函数原型如下:

    int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, 
    redisDisconnectCallback *fn);

    Sending commands and their callbacks

    异步上下文中,由于事件循环的性质,命令会自动进行流水线处理。因此,与同步
    API不同,发送命令只有一种方法。因为命令是异步发送给Redis的,所以发出一个
    命令需要一个回调函数在收到回复时调用。 回复回调应该有以下原型:

    void(redisAsyncContext *c, void *reply, void *privdata);

    参数private可以保存任意需要传递给回调函数的数据,数据可以来自命令开始执
    行入队到开始执行回调函数之间的任意数据。

    可用于在异步上下文中发出命令的函数是:

    int redisAsyncCommand(
      redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
      const char *format, ...);
    int redisAsyncCommandArgv(
      redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
      int argc, const char **argv, const size_t *argvlen);

    这两个功能都像阻塞的API那样工作。 命令返回值是REDIS_OK表示已成功添加到
    输出缓冲区,否则就是REDIS_ERR。例如,当每个用户请求断开连接时,不会有
    新的命令添加到输出缓冲区,并且在调用redisAsyncCommand系列函数时返回
    REDIS_ERR
    如果读取了具有NULL回调的命令的回复,则立即释放该回复。当一个命令的回
    调不是NULL时,内存在回调后立即被释放:回复数据仅在回调期间有效。
    当上下文遇到错误时,所有挂起的回调函数都会得到NULL的回复。

    Disconnecting

    异步连接可以使用以下命令来终止:

    void redisAsyncDisconnect(redisAsyncContext *ac);

    当这个函数被调用时,连接是not立即终止。相反,新命令不再被接受,连接
    只有在所有待处理的命令已经写入套接字,并且它们各自的应答已经被读取并且它
    们各自的回调已经被执行,连接才会终止。之后,断开回调以“REDIS_OK”状态执
    行,上下文对象被释放。

    Hooking it up to event library X

    上下文对象创建后需要设置几个钩子函数。参考与libevlibevent绑定的
    apapters/

    Reply parsing API

    Hiredis提供了回复解析API,可以轻松编写更高级别的语言绑定。
    回复解析API由以下功能组成:

    redisReader *redisReaderCreate(void);
    void redisReaderFree(redisReader *reader);
    int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
    int redisReaderGetReply(redisReader *reader, void **reply);

    在创建正常的Redis上下文时,hiredis在内部使用相同的一组函数,上面的API只是
    将其公开给用户以供直接使用。

    Usage

    函数redisReaderCreate创建一个redisReader结构,它为协议解析器保存一个
    缓冲区,其中包含未分析的数据和状态。

    传入数据 - 很可能来自套接字 - 可以使用redisReaderFeed放置在redisReader
    的内部缓冲区中。 这个函数会对由buf指向的长度为len缓冲区做一个拷贝 这
    个数据在调用redisReaderGetReply时被解析。 这个函数通过void ** reply
    回一个整数状态和一个回复对象(如上所述)。 返回的状态可以是REDIS_OK
    REDIS_ERR,后者意味着出了问题(协议错误或内存不足错误)。

    解析器将多个批量有效负载的嵌套级别限制为7.如果多重批量嵌套级别高于此值,
    解析器将返回一个错误。

    Customizing replies

    函数redisReaderGetReply创建redisReply,并使函数参数reply指向创建
    redisReply变量。 例如,如果“REDIS_REPLY_STATUS”类型的响应,
    则“redisReply”的“str”字段将保持状态为香草C字符串(a vanilla C string)。 但是,
    负责创建redisReply实例的函数可以通过在redisReader结构中设置fn字段
    来定制。 这应该在创建redisReader之后立即完成。例如,[hiredis-rb](https://
    github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c),使用自定
    义的回复对象函数来创建

    Reader max buffer

    当直接使用Reader API或通过普通的Redis上下文间接使用Reader API时,
    redisReader结构使用缓冲区来累积服务器的数据。

    通常这个缓冲区在空并且大于16 KiB的时候被释放,以避免在未使用的缓冲区中浪
    费内存。

    但是,当处理非常大的有效载荷时,破坏缓冲区可能会显着降低性能,因此可以修
    改空闲缓冲区的最大大小,将读取器结构的maxbuf字段的值更改为所需的值。 0的
    特殊值意味着空闲缓冲区没有最大值,所以缓冲区永远不会被释放。

    例如,如果你有一个正常的Redis上下文,你可以设置最大空闲缓冲区为零(无
    限),只需:

    context->reader->maxbuf = 0;

    这应该只是为了在处理大型有效载荷时使性能最大化。 应尽快将上下文重新设置为
    REDIS_READER_MAX_BUF,以防止分配无用的内存。

    作者

    Hiredis是由Salvatore Sanfilippo(gmail的antirez)和Peter Noordhuis(gmail的
    pcnoordhuis)编写的,并且在BSD许可下发布。

    Hiredis目前由Matt Stancliff(genges dot com的matt)和Jan-Erik Rediger
    (fnordig dot com的janerik)负责维护

    展开全文
  • hiredis

    2019-07-13 10:47:49
    hiredis是redis开源库对外发布的客户端API包。 当redis-server配置启动后,可以通过hiredis操作redis资源。 主要分为:  strings、hash、lists、sets、sort sets hiredis使用较为简单,下面是几个主要的函数和...

    hiredis是redis开源库对外发布的客户端API包。

    当redis-server配置启动后,可以通过hiredis操作redis资源。

    主要分为:

      strings、hash、lists、sets、sort sets

    hiredis使用较为简单,下面是几个主要的函数和对象:

     /*
    作用:用于连接redis服务器
     ip : 为redis的ip地址;
     port: 端口地址;
     tv:连接超时的参数;
    */
     redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv);

     

    /*
    作用:执行命令
    c:redisConnectWitTimeout返回的对象;
    format:命令参数;
    */
    
    void *redisCommand(redisContext *c, const char *format, ...)
     /*
     说明:redisCommand返回的对象指针,也就是已经命令返回的结果数据
    */
     
     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;

     

     

    来一个具体的实例

     1 /*需要配置,才能编译通过*/
     2 #include <iostream>
     3 #include "hiredis.h"
     4 
     5 #define MAX_LEN  64
     6 
     7 int main()
     8 {
     9     timeval timeout = {1,500000};
    10     char ip[MAX_LEN],passwd[MAX_LEN];
    11     memset(ip,0,MAX_LEN);
    12     memset(passwd,0,MAX_LEN);
    13     sprintf(ip,"*****");
    14     sprintf(passwd,"******");
    15     uint32_t port = 6379;
    16     redisContext  *m_pRedisContext = redisConnectWithTimeout(ip,port,timeout);
    17     if(m_pRedisContext->err){
    18         std::cout << "log, redis connect error\n";
    19         return 0;
    20     }
    21     
    22     redisReply *reply = static_cast<redisReply*>(redisCommand(m_pRedisContext,\
    23                 "AUTH %s",passwd));
    24     if(!reply){
    25         std::cout << "log, redis command error, " << m_pRedisContext->errstr << \
    26             std::endl;
    27         return 0;
    28     }
    29 
    30     std::cout << "AUTH " << passwd << reply->str << std::endl;
    31     freeReplyObject(reply);
    32    
    33     //create datadase id = 1;
    34     uint32_t index  = 1;
    35     reply = static_cast<redisReply*>(redisCommand(m_pRedisContext,"SELECT %d",1));
    36     if(!reply) {
    37         std::cout << "log, redis command error," << m_pRedisContext->errstr << \
    38             std::endl;
    39         freeReplyObject(reply);
    40         return 0;
    41     }
    42 
    43     std::cout << "SELECT " << index << reply->str << std::endl;
    44     freeReplyObject(reply);
    45     
    46     uint32_t id = 1;
    47     reply = static_cast<redisReply*>(redisCommand(m_pRedisContext, \
    48                 "HMSET user:%u %s %s %s %s",id,"name","xuxu","age","24"));
    49     if(!reply){
    50         std::cout << "log, redis command error," << m_pRedisContext->errstr << \
    51             std::endl;
    52         freeReplyObject(reply);
    53         return 0;
    54     }
    55     
    56     reply = static_cast<redisReply*>(redisCommand(m_pRedisContext,\
    57                 "SET name:%s %s","1","liushun"));
    58     if(!reply){
    59         std::cout << "log, redis command error, " << m_pRedisContext->errstr << \
    60             std::endl;
    61         freeReplyObject(reply);
    62         return 0;
    63   }
    64 
    65     reply = static_cast<redisReply*>(redisCommand(m_pRedisContext,"GET name:%s","1"));
    66     if(!reply){
    67         std::cout << "log, redis command error," << m_pRedisContext->errstr << \
    68             std::endl;
    69         freeReplyObject(reply);
    70         return 0;
    71     }
    72 
    73     std::cout << reply->str << std::endl;
    74     freeReplyObject(reply);
    75   
    76     return 0;
    77 }

     

     

     

     

    转载于:https://www.cnblogs.com/xuxu8511/p/3240941.html

    展开全文
  • HIREDIS

    2018-03-01 10:07:00
    Hiredis is a minimalistic C client library for theRedisdatabase. It is minimalistic because it just adds minimal support for the protocol, but at the same time it uses a high ...

    Hiredis is a minimalistic C client library for the Redis database.

    It is minimalistic because it just adds minimal support for the protocol, but at the same time it uses a high level printf-alike API in order to make it much higher level than otherwise suggested by its minimal code base and the lack of explicit bindings for every Redis command.

    Apart from supporting sending commands and receiving replies, it comes with a reply parser that is decoupled from the I/O layer. It is a stream parser designed for easy reusability, which can for instance be used in higher level language bindings for efficient reply parsing.

    Hiredis only supports the binary-safe Redis protocol, so you can use it with any Redis version >= 1.2.0.

    The library comes with multiple APIs. There is the synchronous API, the asynchronous API and the reply parsing API.

    Upgrading to 1.0.0

    Version 1.0.0 marks a stable release of hiredis. It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory. It also bundles the updated sds library, to sync up with upstream and Redis. For most applications a recompile against the new hiredis should be enough. For code changes see the Changelog.

    Upgrading from <0.9.0

    Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing code using hiredis should not be a big pain. The key thing to keep in mind when upgrading is that hiredis >= 0.9.0 uses a redisContext* to keep state, in contrast to the stateless 0.0.1 that only has a file descriptor to work with.

    Synchronous API

    To consume the synchronous API, there are only a few function calls that need to be introduced:

    redisContext *redisConnect(const char *ip, int port);
    void *redisCommand(redisContext *c, const char *format, ...);
    void freeReplyObject(void *reply);

    Connecting

    The function redisConnect is used to create a so-called redisContext. The context is where Hiredis holds state for a connection. The redisContext struct has an integer err field that is non-zero when the connection is in an error state. The field errstr will contain a string with a description of the error. More information on errors can be found in the Errorssection. After trying to connect to Redis using redisConnect you should check the err field to see if establishing the connection was successful:

    redisContext *c = redisConnect("127.0.0.1", 6379);
    if (c == NULL || c->err) {
        if (c) {
            printf("Error: %s\n", c->errstr);
            // handle error
        } else {
            printf("Can't allocate redis context\n");
        }
    }

    Note: A redisContext is not thread-safe.

    Sending commands

    There are several ways to issue commands to Redis. The first that will be introduced is redisCommand. This function takes a format similar to printf. In the simplest form, it is used like this:

    reply = redisCommand(context, "SET foo bar");

    The specifier %s interpolates a string in the command, and uses strlen to determine the length of the string:

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

    When you need to pass binary safe strings in a command, the %b specifier can be used. Together with a pointer to the string, it requires a size_t length argument of the string:

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

    Internally, Hiredis splits the command in different arguments and will convert it to the protocol used to communicate with Redis. One or more spaces separates arguments, so you can use the specifiers anywhere in an argument:

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

    Using replies

    The return value of redisCommand holds a reply when the command was successfully executed. When an error occurs, the return value is NULL and the err field in the context will be set (see section on Errors). Once an error is returned the context cannot be reused and you should set up a new connection.

    The standard replies that redisCommand are of the type redisReply. The type field in the redisReply should be used to test what kind of reply was received:

    • REDIS_REPLY_STATUS:

      • The command replied with a status reply. The status string can be accessed using reply->str. The length of this string can be accessed using reply->len.
    • REDIS_REPLY_ERROR:

      • The command replied with an error. The error string can be accessed identical to REDIS_REPLY_STATUS.
    • REDIS_REPLY_INTEGER:

      • The command replied with an integer. The integer value can be accessed using the reply->integer field of type long long.
    • REDIS_REPLY_NIL:

      • The command replied with a nil object. There is no data to access.
    • REDIS_REPLY_STRING:

      • A bulk (string) reply. The value of the reply can be accessed using reply->str. The length of this string can be accessed using reply->len.
    • REDIS_REPLY_ARRAY:

      • A multi bulk reply. The number of elements in the multi bulk reply is stored in reply->elements. Every element in the multi bulk reply is a redisReply object as well and can be accessed via reply->element[..index..]. Redis may reply with nested arrays but this is fully supported.

    Replies should be freed using the freeReplyObject() function. Note that this function will take care of freeing sub-reply objects contained in arrays and nested arrays, so there is no need for the user to free the sub replies (it is actually harmful and will corrupt the memory).

    Important: the current version of hiredis (0.10.0) frees replies when the asynchronous API is used. This means you should not call freeReplyObject when you use this API. The reply is cleaned up by hiredis after the callback returns. This behavior will probably change in future releases, so make sure to keep an eye on the changelog when upgrading (see issue #39).

    Cleaning up

    To disconnect and free the context the following function can be used:

    void redisFree(redisContext *c);

    This function immediately closes the socket and then frees the allocations done in creating the context.

    Sending commands (cont'd)

    Together with redisCommand, the function redisCommandArgv can be used to issue commands. It has the following prototype:

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

    It takes the number of arguments argc, an array of strings argv and the lengths of the arguments argvlen. For convenience, argvlen may be set to NULL and the function will use strlen(3) on every argument to determine its length. Obviously, when any of the arguments need to be binary safe, the entire array of lengths argvlen should be provided.

    The return value has the same semantic as redisCommand.

    Pipelining

    To explain how Hiredis supports pipelining in a blocking connection, there needs to be understanding of the internal execution flow.

    When any of the functions in the redisCommand family is called, Hiredis first formats the command according to the Redis protocol. The formatted command is then put in the output buffer of the context. This output buffer is dynamic, so it can hold any number of commands. After the command is put in the output buffer, redisGetReply is called. This function has the following two execution paths:

    1. The input buffer is non-empty:
      • Try to parse a single reply from the input buffer and return it
      • If no reply could be parsed, continue at 2
    2. The input buffer is empty:
      • Write the entire output buffer to the socket
      • Read from the socket until a single reply could be parsed

    The function redisGetReply is exported as part of the Hiredis API and can be used when a reply is expected on the socket. To pipeline commands, the only things that needs to be done is filling up the output buffer. For this cause, two commands can be used that are identical to the redisCommand family, apart from not returning a reply:

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

    After calling either function one or more times, redisGetReply can be used to receive the subsequent replies. The return value for this function is either REDIS_OK or REDIS_ERR, where the latter means an error occurred while reading a reply. Just as with the other commands, the err field in the context can be used to find out what the cause of this error is.

    The following examples shows a simple pipeline (resulting in only a single call to write(2) and a single call to read(2)):

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

    This API can also be used to implement a blocking subscriber:

    reply = redisCommand(context,"SUBSCRIBE foo");
    freeReplyObject(reply);
    while(redisGetReply(context,&reply) == REDIS_OK) {
        // consume message
        freeReplyObject(reply);
    }

    Errors

    When a function call is not successful, depending on the function either NULL or REDIS_ERR is returned. The err field inside the context will be non-zero and set to one of the following constants:

    • REDIS_ERR_IO: There was an I/O error while creating the connection, trying to write to the socket or read from the socket. If you included errno.h in your application, you can use the global errno variable to find out what is wrong.

    • REDIS_ERR_EOF: The server closed the connection which resulted in an empty read.

    • REDIS_ERR_PROTOCOL: There was an error while parsing the protocol.

    • REDIS_ERR_OTHER: Any other error. Currently, it is only used when a specified hostname to connect to cannot be resolved.

    In every case, the errstr field in the context will be set to hold a string representation of the error.

    Asynchronous API

    Hiredis comes with an asynchronous API that works easily with any event library. Examples are bundled that show using Hiredis with libev and libevent.

    Connecting

    The function redisAsyncConnect can be used to establish a non-blocking connection to Redis. It returns a pointer to the newly created redisAsyncContext struct. The err field should be checked after creation to see if there were errors creating the connection. Because the connection that will be created is non-blocking, the kernel is not able to instantly return if the specified host and port is able to accept a connection.

    Note: A redisAsyncContext is not thread-safe.

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("Error: %s\n", c->errstr);
        // handle error
    }

    The asynchronous context can hold a disconnect callback function that is called when the connection is disconnected (either because of an error or per user request). This function should have the following prototype:

    void(const redisAsyncContext *c, int status);

    On a disconnect, the status argument is set to REDIS_OK when disconnection was initiated by the user, or REDIS_ERR when the disconnection was caused by an error. When it is REDIS_ERR, the err field in the context can be accessed to find out the cause of the error.

    The context object is always freed after the disconnect callback fired. When a reconnect is needed, the disconnect callback is a good point to do so.

    Setting the disconnect callback can only be done once per context. For subsequent calls it will return REDIS_ERR. The function to set the disconnect callback has the following prototype:

    int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);

    Sending commands and their callbacks

    In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. Therefore, unlike the synchronous API, there is only a single way to send commands. Because commands are sent to Redis asynchronously, issuing a command requires a callback function that is called when the reply is received. Reply callbacks should have the following prototype:

    void(redisAsyncContext *c, void *reply, void *privdata);

    The privdata argument can be used to curry arbitrary data to the callback from the point where the command is initially queued for execution.

    The functions that can be used to issue commands in an asynchronous context are:

    int redisAsyncCommand(
      redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
      const char *format, ...);
    int redisAsyncCommandArgv(
      redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
      int argc, const char **argv, const size_t *argvlen);

    Both functions work like their blocking counterparts. The return value is REDIS_OK when the command was successfully added to the output buffer and REDIS_ERR otherwise. Example: when the connection is being disconnected per user-request, no new commands may be added to the output buffer and REDIS_ERR is returned on calls to the redisAsyncCommand family.

    If the reply for a command with a NULL callback is read, it is immediately freed. When the callback for a command is non-NULL, the memory is freed immediately following the callback: the reply is only valid for the duration of the callback.

    All pending callbacks are called with a NULL reply when the context encountered an error.

    Disconnecting

    An asynchronous connection can be terminated using:

    void redisAsyncDisconnect(redisAsyncContext *ac);

    When this function is called, the connection is not immediately terminated. Instead, new commands are no longer accepted and the connection is only terminated when all pending commands have been written to the socket, their respective replies have been read and their respective callbacks have been executed. After this, the disconnection callback is executed with theREDIS_OK status and the context object is freed.

    Hooking it up to event library X

    There are a few hooks that need to be set on the context object after it is created. See the adapters/ directory for bindings to libev and libevent.

    Reply parsing API

    Hiredis comes with a reply parsing API that makes it easy for writing higher level language bindings.

    The reply parsing API consists of the following functions:

    redisReader *redisReaderCreate(void);
    void redisReaderFree(redisReader *reader);
    int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
    int redisReaderGetReply(redisReader *reader, void **reply);

    The same set of functions are used internally by hiredis when creating a normal Redis context, the above API just exposes it to the user for a direct usage.

    Usage

    The function redisReaderCreate creates a redisReader structure that holds a buffer with unparsed data and state for the protocol parser.

    Incoming data -- most likely from a socket -- can be placed in the internal buffer of the redisReader using redisReaderFeed. This function will make a copy of the buffer pointed to by buf for len bytes. This data is parsed when redisReaderGetReplyis called. This function returns an integer status and a reply object (as described above) via void **reply. The returned status can be either REDIS_OK or REDIS_ERR, where the latter means something went wrong (either a protocol error, or an out of memory error).

    The parser limits the level of nesting for multi bulk payloads to 7. If the multi bulk nesting level is higher than this, the parser returns an error.

    Customizing replies

    The function redisReaderGetReply creates redisReply and makes the function argument reply point to the created redisReply variable. For instance, if the response of type REDIS_REPLY_STATUS then the str field of redisReply will hold the status as a vanilla C string. However, the functions that are responsible for creating instances of the redisReply can be customized by setting the fn field on the redisReader struct. This should be done immediately after creating the redisReader.

    For example, hiredis-rb uses customized reply object functions to create Ruby objects.

    Reader max buffer

    Both when using the Reader API directly or when using it indirectly via a normal Redis context, the redisReader structure uses a buffer in order to accumulate data from the server. Usually this buffer is destroyed when it is empty and is larger than 16 KiB in order to avoid wasting memory in unused buffers

    However when working with very big payloads destroying the buffer may slow down performances considerably, so it is possible to modify the max size of an idle buffer changing the value of the maxbuf field of the reader structure to the desired value. The special value of 0 means that there is no maximum value for an idle buffer, so the buffer will never get freed.

    For instance if you have a normal Redis context you can set the maximum idle buffer to zero (unlimited) just with:

    context->reader->maxbuf = 0;

    This should be done only in order to maximize performances when working with large payloads. The context should be set back to REDIS_READER_MAX_BUF again as soon as possible in order to prevent allocation of useless memory.

    AUTHORS

    Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
    Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and Jan-Erik Rediger (janerik at fnordig dot com)






    本文作者:陈群
    本文来自云栖社区合作伙伴rediscn,了解相关信息可以关注redis.cn网站。
    展开全文
  • Hiredis is a minimalistic C client library for the Redis database. It is minimalistic because it just adds minimal support for the protocol, but at the same time it uses a high level printf-alike API ...
  • hiredis源码

    2017-03-13 17:30:47
    hiredis源码
  • c++使用hiredis 和封装的客户端 访问redis
  • 招聘信息 ... 要将hiredis与redis-rb结合使用,您需要在创建新连接之前要求redis/connection/hiredis 。 这样可以确保使用hiredis代替纯Ruby连接代码和协议解析器。 在Gemfile中这样做是通过在添加redis-r
  • 用于带有hiredis解析器的redis Hapi(^ 8.0)插件。 为什么用它代替简单的hapi-redis? hiredis解析器比默认情况下随节点redis模块附带的普通javascript解析器要快得多。 支持URL。 至少对我而言,这很重要,因为...
  • 聘请 用于OCaml的Hiredis绑定。 依存关系 Topkg(内部版本) 体重 安装 opam install hiredis 文献资料 参见
  • hiredis-0.13.1

    2016-08-08 14:35:08
    hiredis-0.13.1

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,022
精华内容 2,008
关键字:

hiredis

redis 订阅