首页 技术 正文
技术 2022年11月8日
0 收藏 458 点赞 1,402 浏览 7111 个字

  在菜鸟教程自学了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

 {
"IP" : "127.0.0.1" ,
"PORT" :
}

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

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

 #include "redisConf.h"
#include <stdlib.h>
#include <json/json.h>
#include <string>
#include <iostream>
#include <fstream> namespace ccx{ using std::ifstream;
using std::cout;
using std::endl; RedisConf::RedisConf()
{
getConf();
} void RedisConf::getConf()
{
ifstream ifs;
ifs.open("redisConf.json");
if(!ifs.good())
{
cout << "open RedisConf.json error" << endl;
exit(EXIT_FAILURE);
} Json::Value root;
Json::Reader reader;
if(!reader.parse(ifs, root, false))
{
cout << "RedisConf json reader error" << endl;
exit(EXIT_FAILURE);
} _ip = root["IP"].asString();
_port = root["PORT"].asInt();
ifs.close();
} string RedisConf::getIP()
{
return _ip;
} int RedisConf::getPort()
{
return _port;
} }

  

  然后是目前的redis类:

redis.h

 #ifndef __REDIS_H__
#define __REDIS_H__ #include "redisConf.h" #include <hiredis/hiredis.h> namespace ccx{ class Redis
{
public:
Redis();
public:
void Connect();
void disConnect();
public:
void setString(const string & key, const string & value);
void setString(const string & key, const int & value);
void setString(const string & key, const float & value);
private:
void setString(const string & data);
public:
void getString(const string & key, string & value);
void getString(const string & key, int & value);
void getString(const string & key, float & value);
private:
void getString(const string & key);
private:
void freeReply();
bool isError();
private:
RedisConf _conf;
redisContext * _context;
redisReply * _reply;
};
} #endif

  

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

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

 void Redis::Connect()
{
_context = ::redisConnect(_conf.getIP().c_str(), _conf.getPort());
cout << _conf.getIP() << "-" << _conf.getPort() << endl;
if(_context && _context->err)
{
cout << "connect redis error" << endl;
exit(EXIT_FAILURE);
}
cout << "redis Connect success" << endl;
}

  

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

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

 void Redis::disConnect()
{
::redisFree(_context);
cout << "redis disConnect success" << endl;
}

  

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

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

  

  可以这样用:

 char * command = "SET name lili";
reply = (redisReply*)::redisCommand(context, command);
char * s1 = "name";
char * s2 = "lili";
reply = (redisReply*)::redisCommand(context, "SET %s %s", s1, s2);
reply = (redisReply*)::redisCommand(context, "SET name lili");
7 ...

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

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

 void Redis::freeReply()
{
if(_reply)
{
::freeReplyObject(_reply);
_reply = NULL;
}
}

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

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

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

 #define SETSTRING(key, value) \
stringstream ss;\
ss << "SET " << key << " " << value;\
string s;\
getline(ss, s);\
setString(s);
 void Redis::setString(const string & key, const string & value)
{
SETSTRING(key, value);
}
void Redis::setString(const string & key, const int & value)
{
SETSTRING(key, value);
}
void Redis::setString(const string & key, const float & value)
{
SETSTRING(key, value);
}

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

  它们共用的setString方法:

 void Redis::setString(const string & data)
{
freeReply();
_reply = (redisReply*)::redisCommand(_context, data.c_str());
if(!isError())
{
if (!(_reply->type == REDIS_REPLY_STATUS && strcasecmp(_reply->str,"OK") == ))
{
cout << "Failed to execute SET(string)" << endl;
}
}
}

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

 bool Redis::isError()
{
if(NULL == _reply)
{
freeReply();
disConnect();
Connect();
return true;
}
return false;
}

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

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

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

 void Redis::getString(const string & key)
{
freeReply();
_reply = (redisReply*)::redisCommand(_context, "GET %s", key.c_str());
} void Redis::getString(const string & key, string & value)
{
getString(key);
if(!isError() && _reply->type == REDIS_REPLY_STRING)
{
value = _reply->str;
}
} void Redis::getString(const string & key, int & value)
{
getString(key);
if(!isError() && _reply->type == REDIS_REPLY_STRING)
{
value = ::atoi(_reply->str);
}
} void Redis::getString(const string & key, float & value)
{
getString(key);
if(!isError() && _reply->type == REDIS_REPLY_STRING)
{
value = ::atof(_reply->str);
}
}

redis.cc

 #include "redis.h" #include <string.h>
#include <stdlib.h> #include <sstream>
#include <iostream> namespace ccx{ using std::cout;
using std::endl;
using std::stringstream; #define SETSTRING(key, value) \
stringstream ss;\
ss << "SET " << key << " " << value;\
string s;\
getline(ss, s);\
setString(s); Redis::Redis()
: _conf()
{
} void Redis::Connect()
{
_context = ::redisConnect(_conf.getIP().c_str(), _conf.getPort());
cout << _conf.getIP() << "-" << _conf.getPort() << endl;
if(_context && _context->err)
{
cout << "connect redis error" << endl;
exit(EXIT_FAILURE);
}
cout << "redis Connect success" << endl;
} void Redis::disConnect()
{
::redisFree(_context);
cout << "redis disConnect success" << endl;
} void Redis::setString(const string & data)
{
freeReply();
_reply = (redisReply*)::redisCommand(_context, data.c_str());
if(!isError())
{
if (!(_reply->type == REDIS_REPLY_STATUS && strcasecmp(_reply->str,"OK") == ))
{
cout << "Failed to execute SET(string)" << endl;
}
}
} void Redis::setString(const string & key, const string & value)
{
SETSTRING(key, value);
} void Redis::setString(const string & key, const int & value)
{
SETSTRING(key, value);
} void Redis::setString(const string & key, const float & value)
{
SETSTRING(key, value);
} void Redis::getString(const string & key)
{
freeReply();
_reply = (redisReply*)::redisCommand(_context, "GET %s", key.c_str());
} void Redis::getString(const string & key, string & value)
{
getString(key);
if(!isError() && _reply->type == REDIS_REPLY_STRING)
{
value = _reply->str;
}
} void Redis::getString(const string & key, int & value)
{
getString(key);
if(!isError() && _reply->type == REDIS_REPLY_STRING)
{
value = ::atoi(_reply->str);
}
} void Redis::getString(const string & key, float & value)
{
getString(key);
if(!isError() && _reply->type == REDIS_REPLY_STRING)
{
value = ::atof(_reply->str);
}
} void Redis::freeReply()
{
if(_reply)
{
::freeReplyObject(_reply);
_reply = NULL;
}
} bool Redis::isError()
{
if(NULL == _reply)
{
freeReply();
disConnect();
Connect();
return true;
}
return false;
} }

test.cc

 #include "redis.h" #include <string>
#include <iostream> using std::cout;
using std::endl;
using std::string; int main()
{
ccx::Redis redis;
redis.Connect();
redis.setString("name", "lii"); string s;
redis.getString("name", s);
cout << s << endl; redis.setString("age", "");
redis.getString("age", s);
cout << s << endl; int i;
redis.getString("age", i);
cout << i << endl; redis.disConnect();
}

  测试结果如下:

127.0.0.1-
redis Connect success
liiredis disConnect success
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,893
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,422
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,240
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,054
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,683
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,720