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\n", 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\n", c->errstr);
        exit(1);
    }
 
   
    reply = redisCommand(c,"PING");
    printf("PING: %s\n", reply->str);
    freeReplyObject(reply);
 
   
    reply = redisCommand(c,"SET %s %s", "foo", "hello world");
    printf("SET: %s\n", reply->str);
    freeReplyObject(reply);
 
   
    reply = redisCommand(c,"SET %b %b", "bar", 3, "hello", 5);
    printf("SET (binary API): %s\n", reply->str);
 freeReplyObject(reply);
 
   
    reply = redisCommand(c,"GET foo");
    printf("GET foo: %s\n", reply->str);
    freeReplyObject(reply);
 
    reply = redisCommand(c,"INCR counter");
    printf("INCR counter: %lld\n", reply->integer);
    freeReplyObject(reply);
   
    reply = redisCommand(c,"INCR counter");
    printf("INCR counter: %lld\n", 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\n", 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/

hiredis(Synchronous API)的更多相关文章

  1. LWL-Hitokoto API(一言-纯净API)

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:liwanglin12链接:https://blog.lwl12.com/read/hitokoto-api.html来源:L ...

  2. 【转】基于laravel制作APP接口(API)

    这篇文章主要介绍了基于laravel制作APP接口(API)的相关资料,需要的朋友可以参考下 前期准备 前言,为什么做以及要做个啥本人姓小名白,不折不扣编程届小白一名,但是自从大一那会儿接触到编程这件 ...

  3. 怎样调通微信支付及微信发货通知接口(Js API)

    怎样调通微信支付及微信发货通知接口(Js API) 微信支付提供了一个支付測试页面,微信支付正式使用须要測通支付.发货通知接口 .告警接口.维权接口.告警接口.维权接口非常easy.支付界面调通也相对 ...

  4. 阿里云API网关(5)用户指南(调用 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  5. 阿里云API网关(4)快速入门(开放 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  6. 阿里云API网关(3)快速入门(调用 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  7. 集合(从本部分开始涉及API)

    集合(从本部分开始涉及API) 集合是指一个对象容纳了多个对象,这个集合对象主要用来管理维护一系列相似的对象. 数组就是一种对象.(练习:如何编写一个数组程序,并进行遍历.) java.util.*定 ...

  8. 微信小程序,天气预报(百度地图开放平台API)

    小程序看似一种全新的东西,但好在基本上就是曾经HTML,CSS,JS的一个微变版本. 语法和之前一样.只是一些用法和名字(标签)发生了一些变化. 小程序主要就四种扩展名的文件:js,json,wxml ...

  9. SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)

    上个示例(SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API))是基于JavaScript,运行在web browser内去访问REST AP ...

随机推荐

  1. WP8.1学习系列(第十七章)——交互UX之输入和反馈模式

    如果你将 Windows 应用商店应用设计为触摸交互,则可免费获取对触摸板.鼠标.笔和键盘交互的支持.你的用户可以从一种输入法切换到另一种,而不会丧失应用体验的感觉.将键盘插入平板电脑?没问题.你的应 ...

  2. CopyTo 方法详解

    如果你就想复制一个字符串到另一个字符串,可以使用string的静态方法Copy 例如: string a = "hello"; string b = "world&quo ...

  3. Android.mk(3) 宏

    https://www.jianshu.com/p/7c20b299ee63 传统上我们一直称这种东西为makefile中的变量,其实本质上就是一个宏,只是做的是字符串替换.我们何如就把它叫做宏呢. ...

  4. sencha touch 隐藏滚动条样式的几种方式

    如图,当滚动条显示时不是那么的好看   可以通过以下几种方式来隐藏滚动条,而又不影响滚动效果 1.通过css隐藏 /* 隐藏x方向滚动条 */ .x-scroll-bar-x.active { wid ...

  5. jumpserver的安装

    原文地址:http://docs.jumpserver.org/zh/docs/step_by_step.html 为了保证服务器安全,加个堡垒机,所有ssh连接都通过堡垒机来完成,堡垒机也需要有身份 ...

  6. 【JSP】EL函数和自定义EL函数

    简介 EL原本是JSTL1.0中的技术(所以EL和JSTL感情如此好就是自然的了),但是从JSP2.0开始,EL就分离出来纳入了JSP的标准了.但是EL函数还是和JSTL技术绑定在一起.下面将介绍如何 ...

  7. spring jdbcTemplate 操作存储过程

    Spring的SimpleJdbcTemplate将存储过程的调用进行了良好的封装,下面列出使用JdbcTemplate调用Oracle存储过程的三种情况: 一.无返回值的存储过程调用 1.存储过程代 ...

  8. vue--自定义指令进行验证(1)

    实例代码: <template> <div id="app" class="app"> <h3>{{msg}}</h3 ...

  9. 关于Thinkphp访问不正常的问题

    最近遇见了个蹩脚的问题,我放在服务器的项目(thinkphp框架)只能访问默认路径内容,不管你url怎么写的,他就访问默认那个文件.. 对于有强迫症的我来说实在是欺人太甚!!! 于是乎我就抓耳挠腮了. ...

  10. 【紫书】Play on Words UVA - 10129 欧拉回路

    题意:给你1e5个字符串,若前一个的末尾字母等于当前的首字母,则可以连在一起(成语接龙一个意思)判断是否可以将他们连在一起 题解:将首位看作点,单词看作边.变成欧拉回路问题. 判断出入度是否相等,再用 ...