• hiredis(Synchronous API)


    hiredis是一个小型的client端的c库。它只增加了最小对协议的支持,同时它用一个高级别的printf-alike API为了绑定各种redis命令。除了支持发送和接收命令,它还支持对流的解析。hiredis仅支持binary-safe的redis协议,所以需要用的redis版本>=1.2.0. 这个库包括多个API, 包括同步API,异步API和返回的解析API等。
    安装hiredis:
    1)编译完redis后,在/users/denver/rsun/test/redis/redis-2.6.10/deps/hiredis目录下会生成相应的动态链接库libhiredis.so和静态链接库libhiredis.a,
    2)执行make install
    会将头文件和库文件copy到指定的目录中:
    dcmvrh12% make install
    mkdir -p /u1/rsun/test/redis/redis-2.6.10/include/hiredis /u1/rsun/test/redis/redis-2.6.10/lib
    cp -a hiredis.h async.h adapters /u1/rsun/test/redis/redis-2.6.10/include/hiredis
    cp -a libhiredis.so /u1/rsun/test/redis/redis-2.6.10/lib/libhiredis.so.0.10
    cd /u1/rsun/test/redis/redis-2.6.10/lib && ln -sf libhiredis.so.0.10 libhiredis.so.0
    cd /u1/rsun/test/redis/redis-2.6.10/lib && ln -sf libhiredis.so.0 libhiredis.so
    cp -a libhiredis.a /u1/rsun/test/redis/redis-2.6.10/lib
    安装完就可以使用了。
     
    关于hiredis支持的Synchronous API,主要包括以下函数:
    redisContext *redisConnect(const char *ip, int port);
    void *redisCommand(redisContext *c, const char *format, ...);
    void freeReplyObject(void *reply);
    
    1 连接
    redisConnect函数用来生成redisContext。该上下文用来存储connect状态。redisContext结构有一个整形err字段(非0值)用来保存连接的错误状态。字段errstr用来保存错误描述。当通过redisConnect连接redis结束后,可以check err字段来查看连接是否成功。
    redisContext *c = redisConnect("127.0.0.1", 6379);
    if (c != NULL && c->err) {
        printf("Error: %s
    ", c->errstr);
        // handle error
    }
    
    1) redisContext结构体存储中存储错误信息,文件描述符fd,写缓冲区,redisReader类对象指针。
    typedef struct redisContext {
        int err;
        char errstr[128];
        int fd;
        int flags;
        char *obuf;
        redisReader *reader;
    } redisContext;
     
    2) redisConnect函数实现连接到一个redis server上。
    redisContext *redisConnect(const char *ip, int port) {
        redisContext *c = redisContextInit();
        c->flags |= REDIS_BLOCK;  //设置连接类型是阻塞的
        redisContextConnectTcp(c,ip,port,NULL);
        return c;
    }
    • redisContextInit函数用于初始化redisContext结构体指针。
    • redisContextConnectTcp函数的定义位于net.c中
             根据输入的ip和port绑定地址,使用TCP连接,通过getaddrinfo函数;
    创建socket;
    设置socket属性信息(阻塞),通过fcntl函数;
    连接redis server端,通过connect函数;
    设置socket属性信息,通过setsockopt函数;
     
    2 发送命令
    有许多方式来发送命令给redis。redisCommand方法和printf相似:
    reply = redisCommand(context, "SET foo bar");
    
    可以用%s来表示string类型。
    reply = redisCommand(context, "SET foo %s", value);
    
    当需要发送二进制安全的string类型时,需要使用%b,后面跟string类型以及他的长度。
    reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
    
    redisCommand函数实现:
    void *redisCommand(redisContext *c, const char *format, ...) {
        va_list ap;
        void *reply = NULL;
        va_start(ap,format);
        reply = redisvCommand(c,format,ap);
        va_end(ap);
        return reply;
    }
    1) 采用不定参数的函数实现
    2) 调用redisvCommand函数来解析
    • redisvFormatCommand(char **target, const char *format, va_list ap)
    解析format字符串,根据format的内容从ap中取相应的数据;
    • __redisAppendCommand(redisContext *c, char *cmd, size_t len)将格式化的命令写到输出缓冲区中。
    3 返回值
    通过redisCommand函数的返回值来查看是否执行成功。当有错误发生时,返回值为NULL,同时err字段被标示。一旦context返回错误,则该context不能被重用,需要新建一个新的connect。
    REDIS_REPLY_STATUS:
    返回状态,状态字符串被放在reply->str中,状态字符串长度放在reply->len中。
    REDIS_REPLY_ERROR:
    返回错误
    REDIS_REPLY_INTEGER:
    返回整型值,该值被reply->integer接收,类型为long long
    REDIS_REPLY_NIL:
    返回一个nil对象,没有数据被接收。
    REDIS_REPLY_STRING:
    返回一个字符串,字符串被放在reply->str中,字符串长度放在reply->len中。
    REDIS_REPLY_ARRAY:
    多个元素被返回,元素的数量存放在reply->elements中。每个元素的返回值存放在redisReply中。

    返回值需要被释放通过freeReplyObject()函数。
    void freeReplyObject(void *reply)根据reply->type的不同值执行不同的free操作。

    4 清空
    断开及清空context,使用下列函数:
    void redisFree(redisContext *c);
    
    该函数关闭socket,同时做释放操作。
    根据不同对象,执行不同的free操作。
    void redisFree(redisContext *c) {
        if (c->fd > 0)
            close(c->fd);
        if (c->obuf != NULL)
            sdsfree(c->obuf);
        if (c->reader != NULL)
            redisReaderFree(c->reader);
        free(c);
    }

    5 发送命令
    redisCommandArgv函数用来处理多个命令。
    void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
    
    argc中存放命令数量;argv数组中存放string数组,argvlen为数组长度。
    该函数返回值和redisCommand相同。
    函数定义如下:
    void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
        if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
            return NULL;
        return __redisBlockForReply(c);
    }
    • int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen)
    调用redisFormatCommandArgv函数解析输入命令集合
    调用__redisAppendCommand函数格式化的命令放到输出缓冲区中
    • __redisBlockForReply(redisContext *c)命令集合放到缓冲区中
    e.g.:
    #include < stdio.h >
    #include < stdlib.h >
    #include < string.h >
     
    #include "hiredis.h"
     
    int main(void) {
        unsigned int j;
        redisContext *c;
        redisReply *reply;
     
        struct timeval timeout = { 1, 500000 }; // 1.5 seconds
        c = redisConnectWithTimeout((char*)"127.0.0.2", 6379, timeout);
        if (c->err) {
            printf("Connection error: %s ", c->errstr);
            exit(1);
        }
     
       
        reply = redisCommand(c,"PING");
        printf("PING: %s ", reply->str);
        freeReplyObject(reply);
     
       
        reply = redisCommand(c,"SET %s %s", "foo", "hello world");
        printf("SET: %s ", reply->str);
        freeReplyObject(reply);
     
       
        reply = redisCommand(c,"SET %b %b", "bar", 3, "hello", 5);
        printf("SET (binary API): %s ", reply->str);
     freeReplyObject(reply);
     
       
        reply = redisCommand(c,"GET foo");
        printf("GET foo: %s ", reply->str);
        freeReplyObject(reply);
     
        reply = redisCommand(c,"INCR counter");
        printf("INCR counter: %lld ", reply->integer);
        freeReplyObject(reply);
       
        reply = redisCommand(c,"INCR counter");
        printf("INCR counter: %lld ", reply->integer);
        freeReplyObject(reply);
     
       
        reply = redisCommand(c,"DEL mylist");
        freeReplyObject(reply);
        for (j = 0; j < 10; j++) {
            char buf[64];
     
            snprintf(buf,64,"%d",j);
            reply = redisCommand(c,"LPUSH mylist element-%s", buf);
            freeReplyObject(reply);
        }
        reply = redisCommand(c,"LRANGE mylist 0 -1");
        if (reply->type == REDIS_REPLY_ARRAY) {
            for (j = 0; j < reply->elements; j++) {
                printf("%u) %s ", j, reply->element[j]->str);
            }
        }
        freeReplyObject(reply);
     
        return 0;
    }
     
    result:
    dcmvrh12% ./example
    PING: PONG
    SET: OK
    SET (binary API): OK
    GET foo: hello world
    INCR counter: 9
    INCR counter: 10
    0) element-9
    1) element-8
    2) element-7
    3) element-6
    4) element-5
    5) element-4
    6) element-3
    7) element-2
    8) element-1
    9) element-0
     
    refer to:https://github.com/redis/hiredis/
  • 相关阅读:
    smobiler仿京东app搜索页面
    搜索界面设计
    smobiler仿饿了么app筛选页面
    Smobiler低功耗蓝牙连接的过程和参数的含义
    smobiler仿饿了么app搜索页面
    内存分配的几个函数的简单对比分析
    Android仿IOS选择拍照相册底部弹出框
    正则表达式 : 6~16位字符,至少包含数字.字母.符号中的2种
    android 音量键调节无效问题
    windows查看系统过期时间
  • 原文地址:https://www.cnblogs.com/yanzi-meng/p/9018992.html
Copyright © 2020-2023  润新知