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. Shell xargs

    from here 简介之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了xargs命令,例如: 这个命令是错误的find /sbin -perm + ...

  2. canvas练习 - 圆

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. python中字符串(str)的常用处理方法

    str='python String function' 生成字符串变量str='python String function' 字符串长度获取:len(str)例:print '%s length= ...

  4. Elasticsearch学习之head插件安装

    通过elasticseach自带的plugin命令 elasticsearch/bin/plugin -install mobz/elasticsearch-head 如下图:  2. zip包安装 ...

  5. git服务器

    1 关于版本控制版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统.有以下三种版本控制系统:1. 本地版本控制系统许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会 ...

  6. 【转】失效迭代器(Invalidating Iterators)

      当一个容器变化时,指向该容器中元素的迭代器可能失效.这使得在迭代器变化期间改变容器容易出现问题.在这方面,不同的容器提供不同的保障:vectors: 引起内存重新分配的插入运算使所有迭代器失效,插 ...

  7. 成员函数指针与高效C++委托 (delegate)

    下载实例源代码 - 18.5 Kb 下载开发包库文件 - 18.6 Kb 概要 很遗憾, C++ 标准中没能提供面向对象的函数指针. 面向对象的函数指针也被称为闭包(closures) 或委托(del ...

  8. 基于spring-cloud的微服务(2) eureka服务提供方的注册和消费方的消费

    启动Eureka注册中心之后,服务提供方就可以注册到Eureka上去(作为一个Eureka的客户端) 我们使用IDEA提供的spring initializer来新建一个springcloud项目 填 ...

  9. Memcached下载安装、NET对Memcached进行CRUD操作(2)

    Memcached概念.作用.运行原理.特性.不足简单梳理(1) Memcached下载安装.NET对Memcached进行CRUD操作(2) Memcached存Session数据.访问安全性.使用 ...

  10. spark脚本日志输出级别设置

    import org.apache.log4j.{ Level, Logger } Logger.getLogger("org").setLevel(Level.WARN) Log ...