文档章节

windows环境下通过c++使用redis

涩女郎
 涩女郎
发布于 2015/08/23 20:57
字数 2743
阅读 1641
收藏 4
点赞 0
评论 0

1.Windows下Redis的安装使用

Redis是一个key-value存储系统。Redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。本文中,作者分享了在Windows下进行安装和使用Redis的技巧。

Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sortedset --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave。

前言

因为是初次使用,所以是在windows下进行安装和使用,参考了几篇博客,下面整理一下:

安装Redis

官方网站:http://redis.io/   具体使用redis命令和方法请参考官网

官方下载:http://redis.io/download 可以根据需要下载不同版本

windows版:https://github.com/MSOpenTech/redis/tree/2.6

github的资源可以ZIP直接下载的(这个是给不知道的同学友情提示下)。

下载完成后 可以右键解压到 某个硬盘下 比如D:\Redis\redis-2.6。

在D:\Redis\redis-2.6\bin\release下 有两个zip包 一个32位一个64位。

根据自己windows的位数 解压到D:\Redis\redis-2.6根目录下。

2.启动Redis

进入redis目录后 开启服务  (注意加上redis.conf)

1.  redis-server.exe redis.conf 

这个窗口要保持开启  关闭时redis服务会自动关闭

redis会自动保存数据到硬盘 所以图中是我第二次开启时 多了一个 DB loaded from disk 

3.测试使用

另外开启一个命令行窗口 进入redis目录下 (注意修改自己的ip)

1.  redis-cli.exe -h 192.168.10.61 -p 6379 

 

2.   windows环境下通过c++使用redis

环境:VS2010

1.  新建一个Win32 ConsoleApplication工程

2.  将工程属性->C/C++->CodeGeneration->Runtime Library设置为Multi-threadedDebug(Debug版本)或Multi-threaded(Release版本)

3.  将hiredis.h文件放到工程目录下,将hiredis.lib文件放到Debug或Release目录下,总之让程序能找到hiredis.lib文件

 

程序如下:

#include"stdafx.h"

#include"hiredis.h"

 

#pragmacomment(lib, "hiredis.lib")

#pragmacomment(lib, "ws2_32.lib")

 

 void doTest()

 {

     //初始化ws2_32库

     WSADATA wsaData;

     WSAStartup(MAKEWORD(2,1), &wsaData);

 

     int timeout = 10000;

     struct timeval tv;

     tv.tv_sec = timeout /1000;

     tv.tv_usec = timeout *1000;

     //以带有超时的方式链接Redis服务器,同时获取与Redis连接的上下文对象。

     //该对象将用于其后所有与Redis操作的函数。

     redisContext* c = redisConnect((char*)"127.0.0.1",6379);

     if (c->err) {

        redisFree(c);

         return;

     }

     const char* command1 ="set stest1 value9";

     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 &&(strcmp(r->str,"OK")== 0 || strcmp(r->str, "ok") == 0))) {

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

        freeReplyObject(r);

        redisFree(c);

         return;

     }

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

     freeReplyObject(r);

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

 

     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 lengthof 'stest1' is %d.\n",length);

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

 

     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 valueof 'stest1' is %s.\n",r->str);

     freeReplyObject(r);

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

 

     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 toexecute command[%s].\n",command4);

 

     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(2== r->elements);

         return;

     }

     int i;

      for (i = 0; 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 toexecute command[%s].\n",command5);

 

     printf("Begin totest 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;

     }

 */

 

   redisAppendCommand(c,command1);

   redisAppendCommand(c,command2);

   redisAppendCommand(c,command3);

   redisAppendCommand(c,command4);

    redisAppendCommand(c,command5);

     redisReply* reply =NULL;

     //对pipeline返回结果的处理方式,和前面代码的处理方式完全一直,这里就不再重复给出了。

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

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

         freeReplyObject(reply);

        redisFree(c);

     }

     freeReplyObject(reply);

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

 

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

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

        freeReplyObject(reply);

        redisFree(c);

     }

     freeReplyObject(reply);

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

 

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

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

        freeReplyObject(reply);

        redisFree(c);

     }

     freeReplyObject(reply);

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

 

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

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

        freeReplyObject(reply);

        redisFree(c);

     }

     freeReplyObject(reply);

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

 

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

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

        freeReplyObject(reply);

        redisFree(c);

     }

     freeReplyObject(reply);

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

     //由于所有通过pipeline提交的命令结果均已为返回,如果此时继续调用redisGetReply,

     //将会导致该函数阻塞并挂起当前线程,直到有新的通过管线提交的命令结果返回。

     //最后不要忘记在退出前释放当前连接的上下文对象。

     redisFree(c);

     return;

 }

 

 int main()

 {

     doTest();

     return 0;

 }

3.将Redis做为windows服务

Redis的服务器运行时总有个窗口, 感觉很讨厌,发布软件给人的感觉不正规,本打算自己写个服务程序,把Redis-server封装一下,可是发现一篇文章。http://www.cnblogs.com/shanyou/archive/2013/01/17/redis-on-windows.html,原来人家早就有这个功能了。
从https://github.com/MSOpenTech/redis下载了一份Redis 2.6
打算编译一个RedisWatcher,使Redis做为Windows的服务运行。
编译失败。
需要安装Wix,在http://wix.codeplex.com/下载了一个3.8的版本。
安装后进入VS2010重新编译,出现错误LGHT0094,Google了好久,终于找到办法
<EnableProjectHarvesting>True</EnableProjectHarvesting> ,编译成功。

我的系统是XP,运行InstallWatcher.msi,安装成功,在服务里也出现了redis watcher启动类型为自动。
运行服务失败。1053 服务没有及时响应启动或控制请求。
重启系统也没用什么作用。

在Win7下安装InstallWatcher.msi正常,启动服务正常,Redis也可以正常使用。

开始以为是Wix版本太高,降回到3.6还是老样子。


实在没有办法了,用Dependency Walker看了一下,发现使用ADVAPI32.DLL中的EventRegister、EventUnregister、EventWrite三个函数,而我的系统中的advapi32.dll没有这三个函数。查了一下,发现这几个函数要求的最低版本是WidnowsVista。


没办法,手工把这几个函数去掉吧。
在RedisWatcher.h中,将使用这几个函数的位置都直接注释掉,直接返回ERROR_SUCCESS。

编译……成功,然后VS2010会提示,RedisWatcher.h在外部被修改,是否需要更新,更新进来一看。
RedisWatcher.h又回复了我修改之前的状态。
编译出来的exe文件还是老样子
反复了几次,这个文件还是会被自动恢复。

实在没有办法,用Filemon监控哪些进程读写了RedisWatcher.h,大部分都是cl.exe和devenv.exe,偶然发现有个mc.exe
查了一下,发现这个很奇妙的东西。
http://technet.microsoft.com/zh-cn/library/aa385638
在服务程序中将服务的运行的状态写到日志里,这时就要自己生成一个消息表,将这些消息放到程序里,用ReportEvent就能将记录写到日志里
MC.exe是一个可以生成消息资源文件的工具,生成后的文件可以供应用程序或者DLL使用。
会自动生成*.h,*.rc,*.bin 。
在工程的设置里BuildEvents->Pre-Build Event中存在
mc -um $(ProjectName).man -h "$(ProjectDir)\" -z $(ProjectName)
大致看了下mc的文档,发现有个-mof参数,可以生成支持vsita以前的版本。
mc -um -mof $(ProjectName).man -h "$(ProjectDir)\" -z $(ProjectName)
再次生成的RedisWatcher.h的确没有了那三个函数,可是编译出了一堆错误。也没有心情和时间去细研究Wix和mc,就把正常生成的RedisWatcher.h里自动生成的关于写日志的函数全都去掉。再把mc也去掉。
这次编译成功了,安装后服务也能正常启动。暂时算是成功。


InstallWatcher.msi
redis-benchmark.exe
redis-check-aof.exe
redis-check-dump.exe
redis-cli.exe
redis-server.exe
redis.conf
RedisWatcher.exe
RedisWatcher.man
watcher.conf
这些文件复制到redis-2.6\msvs\install\x32目录
然后编译RedisInstall.sln,将会直接生成一个RedisInstall32.msi就可以直接安装,同时选择安装做为服务了。

1.   测试结果

自己写了一个小程序测试下redis数据库的速度如下:

执行100000次hmset user%d key1 value1key2 value2命令用时6.8秒左右

执行1000000次hmset user%d key1value1 key2 value2命令用时70.9秒左右

 

参考资料:

1.Windows下Redis的安装使用

http://os.51cto.com/art/201403/431103.htm

2.c++使用redis

http://www.360doc.com/content/13/0606/11/10072361_290882627.shtml

3.Redis做为windows服务的曲折过程

http://blog.csdn.net/yuanyingtanxi/article/details/17145163

© 著作权归作者所有

共有 人打赏支持
涩女郎
粉丝 35
博文 104
码字总数 160210
作品 0
浦东
高级程序员
C语言/C++编程学习:环境设置

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 06/05 ⋅ 0

C语言/C++编程学习强势之处的体现

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/12 ⋅ 0

c语言编程软件有哪些 Win7下用哪种C语言编译器

C语言是一门历史很长的编程语言,其编译器和开发工具也多种多样,其开发工具包括编译器,现举几个开发工具供大家选择,当然也要根据自己的操作系统来选择适合自己的开发工具 好多刚开始接触c...

mini92 ⋅ 04/20 ⋅ 0

C语言/C++编程新手学习常见问题

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/11 ⋅ 0

windows下vs2013使用C++访问redis

刚开始在windows下使用c++访问reids各种报错,经过网上到处搜方案,终于可以在windows下访问redis了, 特将注意事项记录下来: 1.获取redis Window下的开发库源码,从github获取 windows版:...

xumaojun ⋅ 04/29 ⋅ 0

大神有话说之c++,还在迷茫的朋友可以来看一下

C++ 是一种中级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。C++ 可运行于多种平台上,如 Window...

悟空_b201 ⋅ 05/30 ⋅ 0

Windows上如何使用SWIG (c++ android 示例)

SWIG介绍 SWIG (Simplified Wrapper and Interface Generator) ,即简化包以及接口生成器,为脚本语言(tcl,perl,python等)提供了C和C++的接口。SWIG在1995年在Los Alamos National Laborat...

u014644594 ⋅ 05/28 ⋅ 0

C语言编程学习:屏幕的任意位置输出字符

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/22 ⋅ 0

什么是 C 和 C ++ 标准库?

简要介绍编写C/C ++应用程序的领域,标准库的作用以及它是如何在各种操作系统中实现的。 我已经接触C++一段时间了,一开始就让我感到疑惑的是其内部结构:我所使用的内核函数和类从何而来? ...

oschina ⋅ 04/10 ⋅ 0

C语言/C++编程学习:输出九九乘法表

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

AppDelegate 设置Root相关

self.window = UIWindow.init(frame: UIScreen.main.bounds) self.window?.backgroundColor = UIColor.white self.window?.makeKeyAndVisible() self.window?.rootViewController = RootTabB......

west_zll ⋅ 20分钟前 ⋅ 0

Java并发系列5--倒计时器CountDownLatch

今天讲一个倒计时器工具,叫CountDownLatch。需要这个工具的场景大概有:当所有的小任务都完成之后,再启动大任务。 先看代码: public class CountDownLatchDemo {static final CountDow...

大大枣 ⋅ 21分钟前 ⋅ 0

SpreadJS使用进阶指南 - 使用 NPM 管理你的项目

前言 SpreadJS作为一款性能出众的纯前端电子表格控件,自2015年发布以来,已经被广泛应用于各领域“在线Excel”数据管理项目中。NPM,作为管理Node.js库最有力的手段,解决了很多NodeJS代码部...

葡萄城控件技术团队 ⋅ 22分钟前 ⋅ 0

Mac下IntelliJ IDEA快捷键大全

https://blog.csdn.net/lisongjia123/article/details/54949364

细节探索者 ⋅ 25分钟前 ⋅ 0

建造者模式

1、工厂模式中创建的对象大都是简单的对象 复杂的产品类并且拥有不同的属性特点的管理就需要用到建造者模式 2、建造者模式: 将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以...

职业搬砖20年 ⋅ 26分钟前 ⋅ 0

Mysql数据库开发 怎么优化SQL语句?

 1) 现场抓出慢查询语句 show full processlist;   2) 配置参数:   slow_query_log_file = ON 慢查询开启开关   long_query_time =2 记录大于2秒的sql语句   log_queries_not_usi...

老男孩Linux培训 ⋅ 27分钟前 ⋅ 0

Laravel 安装执行php artisan migrate 出现字段过长错误

最近在自己研究Laravel Laravel版本:5.6 PHP版本:7.1.9 Mysql版本:5.7.19 Apache版本:2.4.27 系统版本:windows10 首先要保证电脑安装了composer,和node.js 执行命令 composer global ...

Marhal ⋅ 32分钟前 ⋅ 0

ELK6.0日志从收集到处理完整版教程(二)

ELK简介 Elasticsearch 开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。也可以认为ElasticSearch是一...

bz_z ⋅ 35分钟前 ⋅ 0

Spark项目之电商用户行为分析大数据平台之(七)数据调研--基本数据结构介绍

目录 一、user_visit_action(Hive表) 1.1 表的结构 1.2 表的说明 二、user_info(Hive表) 2.1 表的结构 2.2 表的说明 三、task(MySQL表) 3.1 表的结构 3.2 表的说明 四、工作流程...

xiaomin0322 ⋅ 40分钟前 ⋅ 0

评分卡模型剖析之一(woe、IV、ROC、信息熵)

信用评分卡模型在国外是一种成熟的预测方法,尤其在信用风险评估以及金融风险控制领域更是得到了比较广泛的使用,其原理是将模型变量WOE编码方式离散化之后运用logistic回归模型进行的一种二...

火力全開 ⋅ 40分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部