封裝hiredis——C++與redis對接(一)(string的SET與GET操做)

redis,總想着像Mysql同樣,在C/C++中進行對接。因而查詢了一些資料,最後找到了hiredis。然而直接用它的話,不免有點不方便。因而,對其進行封裝。ios

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

下載好以後,因爲其自帶Makefile,只要make一下就編譯出靜態庫與動態庫了,接着把頭文件和靜/動態庫放在相應的文件夾裏就能夠了。注意若是使用動態庫,並且是放在/usr/local/lib/裏,得執行ldconfig命令,來更新一下配置,或者得配置一下動態庫路徑。github

安裝好了就是如何使用的事了。面試

學習hiredis主要是參考這兩個連接:redis

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

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

文章給你們分享C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK技術,面試技巧方面的資料分享的https://ke.qq.com/course/417774?flowToken=1011069函數

一共就五個函數。學習

一、redisContext* redisConnect(const char *ip, int port)二、redisContext* redisConnectWithTimeout(const char *ip, int port, timeval tv)三、void redisFree(redisContext *c)四、void *redisCommand(redisContext *c, const char *format...)五、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

 

 

 View Code

 

test.cc

 

 

 View Code

 

測試結果以下:

127.0.0.1-6379

redis Connect success

lii

30

30

redis disConnect success

相關文章
相關標籤/搜索