封装hiredis——C++与redis对接(一)(string的SET与GET操作)
在菜鸟教程自学了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
#ifndef __REDISCONF_H__
#define __REDISCONF_H__
#include <string>
namespace ccx{
using std::string;
class RedisConf
{
public:
RedisConf();
void getConf();
string getIP();
int getPort();
private:
string _ip;
int _port;
};
}
#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
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 }
test.cc
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 }
测试结果如下:
1 127.0.0.1-6379
2 redis Connect success
3 lii
4 30
5 30
6 redis disConnect success
转载于
https://www.cnblogs.com/chinxi/p/6184885.html
本文来自博客园,作者:Mr-xxx,转载请注明原文链接:https://www.cnblogs.com/MrLiuZF/p/14980135.html