在之前的博客中已经非常详细的介绍了Redis的各种操作命令、运行机制和服务器初始化参数配置。本篇博客是该系列博客中的最后一篇,在这里将给出基于Redis客户端组件访问并操作Redis服务器的代码示例。然而需要说明的是,由于Redis官方并未提供基于C接口的Windows平台客户端,因此下面的示例仅可运行于Linux/Unix平台。但是对于使用其它编程语言的开发者而言,如C#和Java,Redis则提供了针对这些语言的客户端组件,通过该方式,同样可以达到基于Windows平台与Redis服务器进行各种交互的目的。
    该篇博客中使用的客户端来自于Redis官方网站,是Redis推荐的基于C接口的客户端组件,见如下链接:
    https://github.com/antirez/hiredis
    在下面的代码示例中,将给出两种最为常用的Redis命令操作方式,既普通调用方式和基于管线的调用方式。
    注:在阅读代码时请留意注释。

 #include <stdio.h>

#include <stdlib.h>

#include <stddef.h>

#include <stdarg.h>

#include <string.h>

#include <assert.h>

#include <hiredis.h>

8

void doTest()

{

int timeout = ;

struct timeval tv;

tv.tv_sec = timeout / ;

tv.tv_usec = timeout * ;

//以带有超时的方式链接Redis服务器,同时获取与Redis连接的上下文对象。
//该对象将用于其后所有与Redis操作的函数。
redisContext* c = redisConnectWithTimeout("192.168.149.137",,tv);

if (c->err) {

redisFree(c);

return;

}

const char* command1 = "set stest1 value1";

redisReply* r = (redisReply*)redisCommand(c,command1);

//需要注意的是,如果返回的对象是NULL,则表示客户端和服务器之间出现严重错误,必须重新链接。
//这里只是举例说明,简便起见,后面的命令就不再做这样的判断了。
if (NULL == r) {

redisFree(c);

return;

}

//不同的Redis命令返回的数据类型不同,在获取之前需要先判断它的实际类型。
//至于各种命令的返回值信息,可以参考Redis的官方文档,或者查看该系列博客的前几篇
//有关Redis各种数据类型的博客。:)
//字符串类型的set命令的返回值的类型是REDIS_REPLY_STATUS,然后只有当返回信息是"OK"
//时,才表示该命令执行成功。后面的例子以此类推,就不再过多赘述了。
if (!(r->type == REDIS_REPLY_STATUS && strcasecmp(r->str,"OK") == )) {

printf("Failed to execute command[%s].\n",command1);

freeReplyObject(r);

redisFree(c);

return;

}

//由于后面重复使用该变量,所以需要提前释放,否则内存泄漏。
freeReplyObject(r);

printf("Succeed to execute command[%s].\n",command1);

44

const char* command2 = "strlen stest1";

r = (redisReply*)redisCommand(c,command2);

if (r->type != REDIS_REPLY_INTEGER) {

printf("Failed to execute command[%s].\n",command2);

freeReplyObject(r);

redisFree(c);

return;

}

int length = r->integer;

freeReplyObject(r);

printf("The length of 'stest1' is %d.\n",length);

printf("Succeed to execute command[%s].\n",command2);

57

const char* command3 = "get stest1";

r = (redisReply*)redisCommand(c,command3);

if (r->type != REDIS_REPLY_STRING) {

printf("Failed to execute command[%s].\n",command3);

freeReplyObject(r);

redisFree(c);

return;

}

printf("The value of 'stest1' is %s.\n",r->str);

freeReplyObject(r);

printf("Succeed to execute command[%s].\n",command3);

69

const char* command4 = "get stest2";

r = (redisReply*)redisCommand(c,command4);

//这里需要先说明一下,由于stest2键并不存在,因此Redis会返回空结果,这里只是为了演示。
if (r->type != REDIS_REPLY_NIL) {

printf("Failed to execute command[%s].\n",command4);

freeReplyObject(r);

redisFree(c);

return;

}

freeReplyObject(r);

printf("Succeed to execute command[%s].\n",command4);

81

const char* command5 = "mget stest1 stest2";

r = (redisReply*)redisCommand(c,command5);

//不论stest2存在与否,Redis都会给出结果,只是第二个值为nil。
//由于有多个值返回,因为返回应答的类型是数组类型。
if (r->type != REDIS_REPLY_ARRAY) {

printf("Failed to execute command[%s].\n",command5);

freeReplyObject(r);

redisFree(c);

//r->elements表示子元素的数量,不管请求的key是否存在,该值都等于请求是键的数量。
assert( == r->elements);

return;

}

for (int i = ; i < r->elements; ++i) {

redisReply* childReply = r->element[i];

//之前已经介绍过,get命令返回的数据类型是string。
//对于不存在key的返回值,其类型为REDIS_REPLY_NIL。
if (childReply->type == REDIS_REPLY_STRING)

printf("The value is %s.\n",childReply->str);

}

//对于每一个子应答,无需使用者单独释放,只需释放最外部的redisReply即可。
freeReplyObject(r);

printf("Succeed to execute command[%s].\n",command5);

104

printf("Begin to test pipeline.\n");

//该命令只是将待发送的命令写入到上下文对象的输出缓冲区中,直到调用后面的
//redisGetReply命令才会批量将缓冲区中的命令写出到Redis服务器。这样可以
//有效的减少客户端与服务器之间的同步等候时间,以及网络IO引起的延迟。
//至于管线的具体性能优势,可以考虑该系列博客中的管线主题。
if (REDIS_OK != redisAppendCommand(c,command1)

|| REDIS_OK != redisAppendCommand(c,command2)

|| REDIS_OK != redisAppendCommand(c,command3)

|| REDIS_OK != redisAppendCommand(c,command4)

|| REDIS_OK != redisAppendCommand(c,command5)) {

redisFree(c);

return;

}

118

redisReply* reply = NULL;

//对pipeline返回结果的处理方式,和前面代码的处理方式完全一直,这里就不再重复给出了。
if (REDIS_OK != redisGetReply(c,(void**)&reply)) {

printf("Failed to execute command[%s] with Pipeline.\n",command1);

freeReplyObject(reply);

redisFree(c);

}

freeReplyObject(reply);

printf("Succeed to execute command[%s] with Pipeline.\n",command1);

128

if (REDIS_OK != redisGetReply(c,(void**)&reply)) {

printf("Failed to execute command[%s] with Pipeline.\n",command2);

freeReplyObject(reply);

redisFree(c);

}

freeReplyObject(reply);

printf("Succeed to execute command[%s] with Pipeline.\n",command2);

136

if (REDIS_OK != redisGetReply(c,(void**)&reply)) {

printf("Failed to execute command[%s] with Pipeline.\n",command3);

freeReplyObject(reply);

redisFree(c);

}

freeReplyObject(reply);

printf("Succeed to execute command[%s] with Pipeline.\n",command3);

144

if (REDIS_OK != redisGetReply(c,(void**)&reply)) {

printf("Failed to execute command[%s] with Pipeline.\n",command4);

freeReplyObject(reply);

redisFree(c);

}

freeReplyObject(reply);

printf("Succeed to execute command[%s] with Pipeline.\n",command4);

152

if (REDIS_OK != redisGetReply(c,(void**)&reply)) {

printf("Failed to execute command[%s] with Pipeline.\n",command5);

freeReplyObject(reply);

redisFree(c);

}

freeReplyObject(reply);

printf("Succeed to execute command[%s] with Pipeline.\n",command5);

//由于所有通过pipeline提交的命令结果均已为返回,如果此时继续调用redisGetReply,
//将会导致该函数阻塞并挂起当前线程,直到有新的通过管线提交的命令结果返回。
//最后不要忘记在退出前释放当前连接的上下文对象。
redisFree(c);

return;

}

166

int main()

{

doTest();

return ;

}

172

//输出结果如下:
//Succeed to execute command[set stest1 value1].
//The length of 'stest1' is 6.
//Succeed to execute command[strlen stest1].
//The value of 'stest1' is value1.
//Succeed to execute command[get stest1].
//Succeed to execute command[get stest2].
//The value is value1.
//Succeed to execute command[mget stest1 stest2].
//Begin to test pipeline.
//Succeed to execute command[set stest1 value1] with Pipeline.
//Succeed to execute command[strlen stest1] with Pipeline.
//Succeed to execute command[get stest1] with Pipeline.
//Succeed to execute command[get stest2] with Pipeline.
//Succeed to execute command[mget stest1 stest2] with Pipeline.

该示例代码已经调试通过,同时也用Valgrind进行了运行时检查,不存在任何内存泄露,特此声明。

Redis学习手册(实例代码)的更多相关文章

  1. Redis学习之路(007)- Redis学习手册(实例代码)

    在之前的博客中已经非常详细的介绍了Redis的各种操作命令.运行机制和服务器初始化参数配置.本篇博客是该系列博客中的最后一篇,在这里将给出基于Redis客户端组件访问并操作Redis服务器的代码示例. ...

  2. SQLite学习手册(实例代码<一>)

    一.获取表的Schema信息:       1). 动态创建表.     2). 根据sqlite3提供的API,获取表字段的信息,如字段数量以及每个字段的类型.     3). 删除该表.     ...

  3. Redis学习手册(目录)

    为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后 ...

  4. Redis学习手册——转载

    转载出处:http://www.cnblogs.com/stephen-liu74/archive/2012/04/16/2370212.html 为什么自己当初要选择Redis作为数据存储解决方案中 ...

  5. Redis学习手册

    为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后 ...

  6. SQL语句学习手册实例版

    SQL语句学习手册实例版 表操作 例1  对于表的教学管理数据库中的表 STUDENTS ,可以定义如下: CREATE  TABLE  STUDENTS (SNO      NUMERIC (6, ...

  7. Redis 学习手册

    一:Redis的简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,和Memcached类似,它支持存储的value类型相对更多,包 ...

  8. Redis学习手册(Key操作命令)

    一.概述: 在该系列的前几篇博客中,主要讲述的是与Redis数据类型相关的命令,如String.List.Set.Hashes和Sorted-Set.这些命 令都具有一个共同点,即所有的操作都是针对与 ...

  9. Redis学习手册(事务)

    一.概述: 和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石.相信对有关系型数据 ...

随机推荐

  1. cto

    CTO(首席技术官)英文Chief Technology Officer,即企业内负责技术的最高负责人.这个名称在1980年代从美国开始时兴.起于做很多研究的大公司,如General Electric ...

  2. Android开发之AlertDialog

    http://www.cnblogs.com/Gaojiecai/archive/2011/12/10/2283156.html http://www.2cto.com/kf/201205/13187 ...

  3. hdu1501Zipper(记忆化搜索)

    http://acm.hdu.edu.cn/showproblem.php?pid=1501 搜了下记忆化搜索是嘛 然后就看到这个题了 不过一不小心看到代码了 代码又那么短 一不小心给记住了 然后看了 ...

  4. bzoj2506

    不知道该给这题贴什么标签了,但是这是一道好题1.注意这道题的询问是满足区间减法的,我们可以把一个询问拆成两个询问离线搞搞,这个思想在后面会见到2.分类的思想,这道题的求相同余数看似很烦,实际上我们发现 ...

  5. VM上成功安装mac os x

    想必很多人在intel . AMD上安装苹果系统,总会遇到很多问题,今天我就将我成功安装的过程给大家分享一下. 下面是我在VM上安装的步骤: 1. 准备软件 OS X Snow Leopard 10. ...

  6. zoj 1033 与其说是搜索,不如说是枚举

    zoj 与其说是搜索,不如说是枚举,只不过是通过搜索来实现的罢了. 主要是要注意好闰年的判断,特别是要注意好一串数字的划分. 题意其实我也看了一个晚上,才渐渐的看懂. 题意: 给你一个字符串,其中包含 ...

  7. C# winform自定义Label控件使其能设置行距

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  8. NEsper事件处理 z

    http://esper.codehaus.org/nesper/documentation/documentation.html 环境配置 NEsper库下载:下载网址 Vs2010环境集成 在项目 ...

  9. STL总结之queue, priority_queue, stack

    之所以把这三个容器放在一起,是因为他们都是容器适配器.   STL中queue就是我们常用的FIFO队列,实现是一个容器适配器,这种数据结构在网络中经常使用.   queue的模板声明: templa ...

  10. HDU-5373 The shortest problem

    The shortest problem http://acm.hdu.edu.cn/showproblem.php?pid=5373 Time Limit: 3000/1500 MS (Java/O ...