在之前的博客中已经非常详细的介绍了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. ANDROID_MARS学习笔记_S02_003_AutoCompleteTextView

    一. public class CountriesActivity extends Activity { protected void onCreate(Bundle icicle) { super. ...

  2. QString内部仍采用UTF-16存储数据且不会改变(一共10种不同情况下的编码)

    出处:https://blog.qt.io/cn/2012/05/16/source-code-must-be-utf-8-and-qstring-wants-it/ 但是注意,这只是QT运行(Run ...

  3. 170. Two Sum III - Data structure design

    题目: Design and implement a TwoSum class. It should support the following operations: add and find. a ...

  4. 【图片处理】cocos2dx png图片压缩处理

    一.介绍 美术用photoshop出图有时候会包含一些无用的信息,这时候image magick可以把这些信息裁掉. 二.使用方法 1.下载并安装Image Magick 2.将脚本里的目录名改成Im ...

  5. 【原创翻译】Reducing Branch Delay to Zero in Pipelined Processors

    在流水线处理器中减少分支延迟到零 Antonio M. Gonzalez and Jose M. Llaberia 摘要 一种减少流水处理器中分支延迟到零的机制将在本文被描述以及评估.这种机制基于多重 ...

  6. MyBatis学习总结1

    MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用 ...

  7. Spring注解@Component、@Repository、@Service、@Controller,@Autowired、@Resource用法

    一.Spring定义bean,@Component.@Repository.@Service 和 @Controller Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥 ...

  8. FAQ_浏览器_ChromeDriver报错

    Started ChromeDriverport=2437version=23.0.1240.0log=D:\workspace\WebdriverTest\chromedriver.log[0704 ...

  9. Flash Builder4.6破解方案(亲测有效)(转)

    转自 http://bbs.9ria.com/thread-139463-1-1.html 当修改Host文件无法破解时,需要修改Flash Builder安装目录下某些文件来达到破解的目的,经网上搜 ...

  10. oracle rac IP详解

    rac环境下vip/public/private IP的区别 每个节点要2块网卡, 3个IP,虚拟IP或者叫做业务IP,单个网卡当掉可以“漂”到其他网卡是继续提供服务 在Oracle RAC环境下,每 ...