封装hiredis——C++与redis对接(一)(string的SET与GET操作)

摘要:
我在新手教程中自学了Redis,一直想用C/C++连接,就像MySQL一样。然后我打听了一些信息,终于找到了希里迪斯。Hiredis直接去git克隆。地址:https://github.com/redis/hiredis 。 以下两个链接是了解hiredis的主要参考:http://blog.csdn.net/gqtcgq/article/details/51344232 http://blog.csdn.net/achelloworld/article/details/41598389?redis的端口号通常为6379,IP地址为127.0.0.1。由于使用了IP和端口号,它们可能会更改。为了避免在需要更改代码时直接修改代码,我编写了一个配置文件:redisConf。json1{2“IP”:“127.0.0.1”,3“PORT”:63794}相应地,有一个类redisConf,它提取配置信息h1#ifndef_redisConf_H__2#define_REDISCONFH__3#include4namespaceccx{5usingstd::string;6classRedisConf7{8public:9RedisCoff();10voidgetConf();11stringgetIP();12intgetPort();13private:14string_IP;15int_PORT;16};17} 18#endifredisconf.cc1#include“redisConf.h”2#include3#include 4#include<string>5#include<iostream>6#include<fstream>78namespaceccx{910usingstd::ifstream;11usingstd::cout;12usingstd:::endl;1314RedisConf::RedisCoff()15{16getConf();17}1819voidRedisConf:getConf)20{21ifstreamifs;22ifs.open;23if(!

  在菜鸟教程自学了redis,总想着像Mysql一样,在C/C++中进行对接。于是查询了一些资料,最后找到了hiredis。然而直接用它的话,难免有点不方便。于是,对其进行封装。

  hiredis直接去git上克隆,地址:https://github.com/redis/hiredis。

  下载好之后,由于其自带Makefile,只要make一下就编译出静态库与动态库了,接着把头文件和静/动态库放在相应的文件夹里就可以了。注意如果使用动态库,而且是放在/usr/local/lib/里,得执行ldconfig命令,来更新一下配置,或者得配置一下动态库路径。

  安装好了就是如何使用的事了。

  学习hiredis主要是参考这两个链接:

  http://blog.csdn.net/gqtcgq/article/details/51344232

  http://blog.csdn.net/achelloworld/article/details/41598389?utm_source=tuicool&utm_medium=referral

  一共就五个函数。

1、redisContext* redisConnect(const char *ip, int port)

2、redisContext* redisConnectWithTimeout(const char *ip, int port, timeval tv)

3、void redisFree(redisContext *c)

4、void *redisCommand(redisContext *c, const char *format...)

5、void freeReplyObject(void *reply)

  和Mysql一样,要对接,第一件事就是用IP和端口号建立连接什么的。redis的端口号一般是6379,IP直接用127.0.0.1就可以了。既然要用到IP和端口号,又是可能会变的东西,为了不使想要改变它们的时候得直接修改代码,我写了个配置文件:

redisConf.json

1 {
2     "IP" : "127.0.0.1" ,
3     "PORT" : 6379
4 }

  相应地,有提取配置信息的类

redisConf.h

 1 #ifndef __REDISCONF_H__
 2 #define __REDISCONF_H__
 3 #include <string>
 4 namespace ccx{
 5 using std::string;
 6 class RedisConf
 7 {
 8     public:
 9         RedisConf();
10         void getConf();
11         string getIP();
12         int getPort();
13     private:
14         string _ip;
15         int _port;
16 };
17 }
18 #endif

redisconf.cc

 1 #include "redisConf.h"
 2 #include <stdlib.h>
 3 #include <json/json.h>
 4 #include <string>
 5 #include <iostream>
 6 #include <fstream>
 7 
 8 namespace ccx{
 9 
10 using std::ifstream;
11 using std::cout;
12 using std::endl;
13 
14 RedisConf::RedisConf()
15 {
16     getConf();
17 }
18 
19 void RedisConf::getConf()
20 {
21     ifstream ifs;
22     ifs.open("redisConf.json");
23     if(!ifs.good())
24     {
25         cout << "open RedisConf.json error" << endl;
26         exit(EXIT_FAILURE);
27     }
28 
29     Json::Value root;
30     Json::Reader reader;
31     if(!reader.parse(ifs, root, false))
32     {
33         cout << "RedisConf json reader error" << endl;
34         exit(EXIT_FAILURE);
35     }
36     
37     _ip = root["IP"].asString();
38     _port = root["PORT"].asInt();
39     ifs.close();
40 }
41 
42 string RedisConf::getIP()
43 {
44     return _ip;
45 }
46 
47 int RedisConf::getPort()
48 {
49     return _port;
50 }
51 
52 }

  

  然后是目前的redis类:

redis.h

 1 #ifndef __REDIS_H__
 2 #define __REDIS_H__
 3 
 4 #include "redisConf.h"
 5 
 6 #include <hiredis/hiredis.h>
 7 
 8 
 9 namespace ccx{
10 
11 class Redis
12 {
13     public:
14         Redis();
15     public:
16         void Connect();
17         void disConnect();
18     public:
19         void setString(const string & key, const string & value);
20         void setString(const string & key, const int & value);
21         void setString(const string & key, const float & value);
22     private:
23         void setString(const string & data);
24     public:
25         void getString(const string & key, string & value);
26         void getString(const string & key, int & value);
27         void getString(const string & key, float & value);
28     private:
29         void getString(const string & key);
30     private:
31         void freeReply();
32         bool isError();
33     private:
34         RedisConf _conf;
35         redisContext * _context;
36         redisReply * _reply;
37 };
38 }
39 
40 #endif

  

  下面结合写好的代码说说前面的五个函数。

  函数1是用来连接redis的,具体如下:

 1 void Redis::Connect()
 2 {
 3     _context = ::redisConnect(_conf.getIP().c_str(), _conf.getPort());
 4     cout << _conf.getIP() << "-" << _conf.getPort() << endl;
 5     if(_context && _context->err)
 6     {
 7         cout << "connect redis error" << endl;
 8         exit(EXIT_FAILURE);    
 9     }
10     cout << "redis Connect success" << endl;
11 }

  

  函数2是在1的基础上,添加了一个超时功能。

  函数3是在不使用redis了,要断开连接时使用的:

1 void Redis::disConnect()
2 {
3     ::redisFree(_context);
4     cout << "redis disConnect success" << endl;
5 }

  

  函数4稍微复杂一些,有点像C中的printf:

1 printf("%d%s%d",d1,s1,d2);
2 printf("hello,world");

  

  可以这样用:

1 char * command = "SET name lili";
2 reply = (redisReply*)::redisCommand(context, command);
3 char * s1 = "name";
4 char * s2 = "lili";
5 reply = (redisReply*)::redisCommand(context, "SET %s %s", s1, s2);
6 reply = (redisReply*)::redisCommand(context, "SET name lili");
7 ...

  第一个参数context是函数1或者2的返回值,告诉它要与哪里的redis进行交互。reply指向命令结果的存储位置。

  函数5是用来清理函数4 的返回结果的:

1 void Redis::freeReply()
2 {
3     if(_reply)
4     {
5         ::freeReplyObject(_reply);
6         _reply = NULL;
7     }
8 }

  第6行是因为对这个函数不熟,就干脆清完之后给它赋值NULL。

  由于redis的string中存的可能是字符串、整形、浮点数,于是各自重载了三个版本的get与set方法,并重用一些函数,以减少代码量。

  对于set,直接用一个宏替换:

1 #define SETSTRING(key, value) 
2     stringstream ss;
3     ss << "SET " << key << " " << value;
4     string s;
5     getline(ss, s);
6     setString(s);
 1 void Redis::setString(const string & key, const string & value)
 2 {
 3     SETSTRING(key, value);
 4 }
 5 void Redis::setString(const string & key, const int & value)
 6 {
 7     SETSTRING(key, value);
 8 }
 9 void Redis::setString(const string & key, const float & value)
10 {
11     SETSTRING(key, value);
12 }

  使用C++中的stringstream,会比用“%d”、“%s”、“%f”来区分类型少些代码。两种方法的结果是相同的。

  它们共用的setString方法:

 1 void Redis::setString(const string & data)
 2 {
 3     freeReply();
 4     _reply = (redisReply*)::redisCommand(_context, data.c_str());
 5     if(!isError())
 6     {
 7         if (!(_reply->type == REDIS_REPLY_STATUS && strcasecmp(_reply->str,"OK") == 0))
 8         {
 9             cout << "Failed to execute SET(string)" << endl;
10         }    
11     }
12 }

  这里的isError是用来判断是否连接异常的:

 1 bool Redis::isError()
 2 {
 3     if(NULL == _reply)
 4     {
 5         freeReply();
 6         disConnect();
 7         Connect();
 8         return true;
 9     }
10     return false;
11 }

  如果连接异常,得断开重连。

  在redis命令行里,如果set成功,会提示“OK”。于是,这里先判断了一下命令结果的数据类型,如果是字符串,再判断它是不是“OK”,以此来判断set是否成功。

  对于get,我试了各种方法,都无法直接从命令结果中提取出数字,暂时还没找到原因。但是数字却可以以字符串格式得到。于是,使用了atoi来处理:

 1 void Redis::getString(const string & key)
 2 {
 3     freeReply();
 4     _reply = (redisReply*)::redisCommand(_context, "GET %s", key.c_str());
 5 }
 6 
 7 void Redis::getString(const string & key, string & value)
 8 {
 9     getString(key);
10     if(!isError() && _reply->type == REDIS_REPLY_STRING)
11     {
12         value = _reply->str;
13     }
14 }
15 
16 void Redis::getString(const string & key, int & value)
17 {
18     getString(key);
19     if(!isError() && _reply->type == REDIS_REPLY_STRING)
20     {
21         value = ::atoi(_reply->str);
22     }
23 }
24 
25 void Redis::getString(const string & key, float & value)
26 {
27     getString(key);
28     if(!isError() && _reply->type == REDIS_REPLY_STRING)
29     {
30         value = ::atof(_reply->str);
31     }
32 }

redis.cc

封装hiredis——C++与redis对接(一)(string的SET与GET操作)第1张封装hiredis——C++与redis对接(一)(string的SET与GET操作)第2张
  1 #include "redis.h"
  2 
  3 #include <string.h>
  4 #include <stdlib.h>
  5 
  6 #include <sstream>
  7 #include <iostream>
  8 
  9 namespace ccx{
 10 
 11 using std::cout;
 12 using std::endl;
 13 using std::stringstream;
 14 
 15 #define SETSTRING(key, value) 
 16     stringstream ss;
 17     ss << "SET " << key << " " << value;
 18     string s;
 19     getline(ss, s);
 20     setString(s);
 21 
 22 Redis::Redis()
 23 : _conf()
 24 {
 25 }
 26 
 27 void Redis::Connect()
 28 {
 29     _context = ::redisConnect(_conf.getIP().c_str(), _conf.getPort());
 30     cout << _conf.getIP() << "-" << _conf.getPort() << endl;
 31     if(_context && _context->err)
 32     {
 33         cout << "connect redis error" << endl;
 34         exit(EXIT_FAILURE);    
 35     }
 36     cout << "redis Connect success" << endl;
 37 }
 38 
 39 void Redis::disConnect()
 40 {
 41     ::redisFree(_context);
 42     cout << "redis disConnect success" << endl;
 43 }
 44 
 45 void Redis::setString(const string & data)
 46 {
 47     freeReply();
 48     _reply = (redisReply*)::redisCommand(_context, data.c_str());
 49     if(!isError())
 50     {
 51         if (!(_reply->type == REDIS_REPLY_STATUS && strcasecmp(_reply->str,"OK") == 0))
 52         {
 53             cout << "Failed to execute SET(string)" << endl;
 54         }    
 55     }
 56 }
 57 
 58 void Redis::setString(const string & key, const string & value)
 59 {
 60     SETSTRING(key, value);
 61 }
 62 
 63 void Redis::setString(const string & key, const int & value)
 64 {
 65     SETSTRING(key, value);
 66 }
 67 
 68 void Redis::setString(const string & key, const float & value)
 69 {
 70     SETSTRING(key, value);
 71 }
 72 
 73 void Redis::getString(const string & key)
 74 {
 75     freeReply();
 76     _reply = (redisReply*)::redisCommand(_context, "GET %s", key.c_str());
 77 }
 78 
 79 void Redis::getString(const string & key, string & value)
 80 {
 81     getString(key);
 82     if(!isError() && _reply->type == REDIS_REPLY_STRING)
 83     {
 84         value = _reply->str;
 85     }
 86 }
 87 
 88 void Redis::getString(const string & key, int & value)
 89 {
 90     getString(key);
 91     if(!isError() && _reply->type == REDIS_REPLY_STRING)
 92     {
 93         value = ::atoi(_reply->str);
 94     }
 95 }
 96 
 97 void Redis::getString(const string & key, float & value)
 98 {
 99     getString(key);
100     if(!isError() && _reply->type == REDIS_REPLY_STRING)
101     {
102         value = ::atof(_reply->str);
103     }
104 }
105 
106 void Redis::freeReply()
107 {
108     if(_reply)
109     {
110         ::freeReplyObject(_reply);
111         _reply = NULL;
112     }
113 }
114 
115 bool Redis::isError()
116 {
117     if(NULL == _reply)
118     {
119         freeReply();
120         disConnect();
121         Connect();
122         return true;
123     }
124     return false;
125 }
126 
127 }
View Code

test.cc

封装hiredis——C++与redis对接(一)(string的SET与GET操作)第1张封装hiredis——C++与redis对接(一)(string的SET与GET操作)第4张
 1 #include "redis.h"
 2 
 3 #include <string>
 4 #include <iostream>
 5 
 6 using std::cout;
 7 using std::endl;
 8 using std::string;
 9 
10 int main()
11 {
12     ccx::Redis redis;
13     redis.Connect();
14     redis.setString("name", "lii");
15 
16     string s;
17     redis.getString("name", s);
18     cout << s << endl;
19 
20     redis.setString("age", "30");
21     redis.getString("age", s);
22     cout << s << endl;
23     
24     int i;
25     redis.getString("age", i);
26     cout << i << endl;    
27 
28     redis.disConnect();
29 }
View Code

  测试结果如下:

127.0.0.1-6379
redis Connect success
lii
30
30
redis disConnect success

免责声明:文章转载自《封装hiredis——C++与redis对接(一)(string的SET与GET操作)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WINCE应用程序开机自运行方法总结(转载)websocket前后端交互下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

谈jdbcTemplate与mybatis

为什么会产生 Hibernate Mybatis 这类的dao层框架 传统的jdbc 虽然执行速度很快,但是开发效率很低,随着面向对象开发的设计思想,在面向对象编程中 将对象 进行持久化,存入关系型的数据库时,由于关系型数据库的设计思想是数学思维,在持久化时,必须要对象拆分各个属性值,才可存入数据库;传统的jdbc 持久化时 对象持久化时 ,取出对象的一个...

微信公众平台开发教程(六)获取个性二维码

微信公众平台开发教程(六)获取个性二维码 一、功能介绍 在进行推广时,我们可以告诉对方,我们的微信公众账号是什么,客户可以去搜索,然后关注。二维码给我们提供了极大的便捷,只要简单一扫描,即可关注。 如果已经关注过,立刻跳入对话画面。在我们进行推广时,不再是简陋的文字,可以是一个有个性的二维码,想必会很生动。 微信对二维码提供了很好的支持,而且还可以根据需要...

Recordset属性与方法

Recordset属性与方法 关于分页:   首先,我们可以为 PageSize 属性设置一个值,从而指定从记录组中取出的构成一个页的行数;然后通过RecordCount 属性来确定记录的总数;再用记录总数除以 PageSize 就可得到所显示的页面总数;最后通过 AbsolutePage 属性就能完成对指定页的访问    ----------------...

Java String.split()函数分隔回车注意事项

作者:Sun1956原文:https://blog.csdn.net/sun1956/article/details/45096117 --------------------- 我们在Java中如果用到处理要分隔字符串,不免会用到String的split(String regex)函数,这时候我们要注意的。 如果想以回车来分隔字符串,很多同学都会这样做。...

Beetl学习总结(2)——基本用法

2.1. 安装 如果使用maven,使用如下坐标 <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>2.7.0</version> </dependen...

基础篇:JAVA.Stream函数,优雅的数据流操作

前言 平时操作集合数据,我们一般都是for或者iterator去遍历,不是很好看。java提供了Stream的概念,它可以让我们把集合数据当做一个个元素在处理,并且提供多线程模式 流的创建 流的各种数据操作 流的终止操作 流的聚合处理 并发流和CompletableFuture的配合使用 关注公众号,一起交流,微信搜一搜: 潜行前行 1 stream的...