萌新笔记——封装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
{
"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
lii redis disConnect success
萌新笔记——封装hiredis——C++与redis对接(一)(string的SET与GET操作)的更多相关文章
- 封装hiredis——C++与redis对接(一)(string的SET与GET操作)
在菜鸟教程自学了redis,总想着像Mysql一样,在C/C++中进行对接.于是查询了一些资料,最后找到了hiredis.然而直接用它的话,难免有点不方便.于是,对其进行封装. hiredis直接去g ...
- 萌新笔记——C++里创建 Trie字典树(中文词典)(三)(联想)
萌新做词典第三篇,做得不好,还请指正,谢谢大佬! 今天把词典的联想做好了,也是比较low的,还改了之前的查询.遍历等代码. Orz 一样地先放上运行结果: test1 ID : char : 件 w ...
- 萌新笔记——C++里创建 Trie字典树(中文词典)(二)(插入、查找、导入、导出)
萌新做词典第二篇,做得不好,还请指正,谢谢大佬! 做好了插入与遍历功能之后,我发现最基本的查找功能没有实现,同时还希望能够把内存的数据存入文件保存下来,并可以从文件中导入词典.此外,数据的路径是存在配 ...
- 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)
萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...
- 萌新笔记之堆(heap)
前言(萌新感想): 以前用STL的queue啊stack啊priority_queue啊,一直很想懂原理,现在终于课上到了priority_queue,还有就是下周期中考,哈哈,所以写几篇blog总结 ...
- 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)
前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...
- 萌新笔记——Cardinality Estimation算法学习(一)(了解基数计算的基本概念及回顾求字符串中不重复元素的个数的问题)
最近在菜鸟教程上自学redis.看到Redis HyperLogLog的时候,对"基数"以及其它一些没接触过(或者是忘了)的东西产生了好奇. 于是就去搜了"HyperLo ...
- 萌新笔记——git的问题(error: object file .git/objects/* is empty...)的解决方案及对git版本库文件的了解
由于操作不当,导致git版本库出了大问题,如下所示: error: object file .git/objects/8b/61d0135d3195966b443f6c73fb68466264c68e ...
- 萌新笔记之Nim取石子游戏
以下笔记摘自计算机丛书组合数学,机械工业出版社. Nim取石子游戏 Nim(来自德语Nimm!,意为拿取)取石子游戏. 前言: 哇咔咔,让我们来追寻娱乐数学的组合数学起源! 游戏内容: 有两个玩家面对 ...
随机推荐
- Python学习--01入门
Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...
- JavaScript高级程序设计--对象,数组(栈方法,队列方法,重排序方法,迭代方法)
1.使用对象字面量定义对象 var person={}; 使用这种方式创建对象时,实际上不会调用Object构造函数. 开发人员更喜欢对象字面量的语法. 2.有时候需要传递大量可选参数的情形时,一 ...
- Kafka 文档用例
1.2 用例 以下是一些Kafka 常见的用例.关于功能方面的一些概念,可以看这篇博客:http://engineering.linkedin.com/distributed-systems/log- ...
- OpenCASCADE Job - Shoe Doctor
鞋博士 鞋博士经过8年沉淀,在鞋类工业4.0全流程平台上积累了相当的技术实力,获投资商亲睐. 新的一年,在投资商协助下,将踏上新的征途,因此诚邀您加盟顶层技术合伙人. 如果您具备以下实力,我们期待您的 ...
- SpringMVC中定时任务配置
在项目中使用定时任务是常有的事,比如每天定时进行数据同步或者备份等等. 以前在从事C语言开发的时候,定时任务都是通过写个shell脚本,然后添加到linux定时任务中进行调度的. 现在使用Spring ...
- MySQL笔记---视图,存储过程, 触发器的使用入门
大二学数据库的时候,只是隐约听到老师提起过视图啊,存储过程啊,触发器啊什么的,但只是淡淡的记住了名字,后来自己做些小项目,小程序,也没有用上过,都只是简单的建表,关联表之类的,导致我对这些东西的理解只 ...
- Docker 基础 : 数据管理
用户在使用 Docker 的过程中,往往需要能查看容器内应用产生的数据,或者需要把容器内的数据进行备份,甚至多个容器之间进行数据的共享,这必然涉及容器的数据管理操作.容器中管理数据主要有两种方式:数据 ...
- JDBC介绍
1.DriverManager用来建立和数据库的链接以及管理JDBC驱动程序 driverManager的常用方法 方法 描述 registerDriver(Driver driver) 在Derve ...
- 高效 Java Web 开发框架 JessMA v3.5.1
JessMA 是功能完备的高性能 Full-Stack Web 应用开发框架,内置可扩展的 MVC Web 基础架构和 DAO 数据库访问组件(内部已提供了 Hibernate.MyBatis 与 J ...
- GJM : Unity3D HIAR -【 快速入门 】 一、简介
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...