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. WinDBG 技巧:列出模块(DLL/EXE)里面所有的符号(symbol)

    想对某个函数下断点,但是记不清楚的函数具体的名字,这个时侯可以使用x命令来列举所有的符号. 命令格式为: x [选项] 模块名字!符号匹配表达式 这里的符号匹配表达式类似dos的文件名匹配表达式,可以 ...

  2. 《转》Python学习(15)-对文件的操作(二)

    转自 http://www.cnblogs.com/BeginMan/p/3169020.html 一.文件系统 从系统角度来看,文件系统是对文件存储器空间进行组织和分配,负责文件存储并对存入的文件进 ...

  3. WP8.1学习系列(第五章)——中心控件Hub或透视控件Pivot交互UX

    具有主页菜单(中心或透视控件)的中心应用中心 你可能要设计包含许多功能的应用.当你看着这些功能时,可能会决定将它们整理到独立的区域中.这些区域最终会成为用户要访问的应用的独立部分.你需要设计一个简便的 ...

  4. USACO The Clocks

    操作间没有次序关系,同一个操作最多重复3次... 可以直接暴力... The Clocks IOI'94 - Day 2 Consider nine clocks arranged in a 3x3 ...

  5. SQL 查询结果保存为 临时表

    -- 1. 在使用select into前,可以先做一下判断 if OBJECT_ID('tempdb..#TT')is not NULL drop table #TT -- 2. 查询结果保存为临时 ...

  6. libevent安装方法

    安装FastDFS之前,先安装libevent工具包,记录一下安装过程 1.检查:ls -al /usr/lib | grep libevent 查看是否已安装,如果已安装且版本低于1.3,则先通过: ...

  7. LeetCode 45 Jump Game II(按照数组进行移动)

    题目链接:https://leetcode.com/problems/jump-game-ii/?tab=Description   给定一个数组,数组中的数值表示在当前位置能够向前跳动的最大距离. ...

  8. docker参数--restart=always的作用

    创建容器时没有添加参数  --restart=always ,导致的后果是:当 Docker 重启时,容器未能自动启动. 现在要添加该参数怎么办呢,方法有二: 1.Docker 命令修改 docker ...

  9. javap(反汇编命令)详解

    javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码.通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作. 语法: javap [ 命令选项 ] class. . ...

  10. 【CF913G】Power Substring 数论+原根

    [CF913G]Power Substring 题意:T组询问,每次给定一个数a,让你求一个k,满足$2^k$的10进制的后$min(100,length(k))$位包含a作为它的子串.你只需要输出一 ...