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学习系列(第六章)——中心控件Hub面板部分交互UX

    本主题中呈现的模型类似于适用于 Windows Phone 的具有主页菜单(中心或透视控件)的中心应用中描述的模型.正如之前的案例所示,你要向用户呈现不同的功能区域.此处的区别在于你可以在顶层呈现所有 ...

  2. 【Spring Boot&&Spring Cloud系列】Spring Boot中使用数据库之MySql

    对于传统关系型数据库来说,Spring Boot使用JPA(Java Persistence API)资源库提供持久化的标准规范,即将Java的普通对象通过对象关系映射(ORM)持久化到数据库中. 项 ...

  3. git查看指令

    打开git bash 1,查看自己之前是否生成过ssh密钥 $ ls .ssh 如果存在这个id_rsa.pub这个文件的话表示已经生成了 2,查看用户名和邮箱 $ git config --glob ...

  4. CF 445A DZY Loves Chessboard

    A. DZY Loves Chessboard time limit per test 1 second memory limit per test 256 megabytes input stand ...

  5. MySQL的ALTER变更、正则查询、分组查询、排序查询以及事务查询的概

    MySQL的表和字段信息的变更 ALTER TABLE table-name DROP column-name; #删除某个字段 ALTER TABLE table-name ADD column-n ...

  6. redmine生产环境搭建

    记录信息: 搭建基础应用及mysql 配置svn 配置自动重启 配置API开放 配置邮箱发送 开启数据库ip访问权限 确认用户组管理:配置用户同步 配置部门同步

  7. node项目部署相关问题

    process.env process.env属性返回一个对象,包含了当前Shell的所有环境变量. 通常的做法是,新建一个环境变量NODE_ENV,用它确定当前所处的开发阶段,生产阶段设为produ ...

  8. /etc/vim/vimrc的一个的配置

    (转)Vim 配置文件===/etc/vimrc "===================================================================== ...

  9. R序列seq

    > seq(from=10,to=20,by=3) [1] 10 13 16 19 > seq(from=10,to=20,length=5) [1] 10.0 12.5 15.0 17. ...

  10. poi 导入导出excel

    import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; i ...