生活随笔
收集整理的這篇文章主要介紹了
Linux下使用C++操作redis数据库
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Linux下使用C++操作redis數據庫
文章目錄
- Linux下使用C++操作redis數據庫
- 一、安裝配置hiredis.h
- 二、接口介紹
- 1.**`建立鏈接:redisConnect`**
- 2.**`執行redis命令:redisCommand`**
- 3.**`釋放redisCommand`**
- 4.**`斷開連接:redisFree`**
- 5.流水線:Pipelining
- 三、簡單封裝hiredis
一、安裝配置hiredis.h
C++來操作redis數據庫。通過hiredis.h接口來實現,目前只能在Linux環境使用。
cd hiredis
- 執行make && make install(自動把libhiredis.so放到/usr/local/lib/中,把hiredis.h放到/usr/local/inlcude/hiredis/中)
make
&& make install
- 接下來在程序中就可以直接用了,在程序中包含#include <hiredis/hiredis.h>即可
- 在編譯代碼的時候需要加鏈接的庫及庫的路徑,假設文件為redis.cpp,那么編譯命令如下
g
++ redis
.cpp
-o redis
-L
/usr
/local
/lib
/ -lhiredis
- 在執行的時候如果出現動態庫無法加載,那么需要進行如下配置
- 在 /etc/ld.so.conf.d/ 目錄下新建文件 usr-libs.conf ,內容是: /usr/local/lib
sudo vim
/etc
/ld
.so
.conf
.d
/usr
-libs
.conf
- 然后使用命令 /sbin/ldconfig 更新一下配置即可。
sudo
/sbin
/ldconfig
二、接口介紹
1.建立鏈接:redisConnect
redisContext
* redisConnect(const char *ip
, int port
)
- 函數解釋
- 該函數用來連接redis數據庫, 兩個參數分別是redis數據庫的ip和端口,端口號一般為6379。
- 該函數redisConnect用于創建所謂的redisContext。上下文是Hiredis保持連接狀態的地方。
- 當連接處于錯誤狀態時,該redisContext 結構具有一個err非零的整數字段。該字段errstr將包含帶有錯誤描述的字符串。
- 使用嘗試連接到Redis后redisConnect,應檢查該err字段以查看建立連接是否成功
- 類似的還提供了一個函數,供連接超時限定,即
redisContext
* redisConnectWithTimeout(const char *ip
, int port
, timeval tv
)。
- 注意注意,官方說明redisConnect函數不是線程安全的
- 使用案例
redisContext
*c
= redisConnect("127.0.0.1", 6379);
if (c
== NULL || c
->err
)
{if (c
) {printf("Error: %s\n", c
->errstr
);} else {printf("Can't allocate redis context\n");}
}
- 錯誤解釋
- 當函數調用不成功時,取決于函數NULL還是REDIS_ERR返回。err上下文中的字段將為非零值,并設置為以下常量之一:
- REDIS_ERR_IO:創建連接,嘗試寫入套接字或從套接字讀取時發生I /O錯誤。如果您包含errno.h在應用程序中,則可以使用全局errno變量來找出問題所在。
- REDIS_ERR_EOF:服務器關閉了連接,導致讀取為空。
- REDIS_ERR_PROTOCOL:解析協議時出錯。
- REDIS_ERR_OTHER:其他任何錯誤。當前,僅在無法解析要連接的指定主機名時使用。
- 在每種情況下,errstr上下文中的字段都將設置為包含錯誤的字符串表示形式。
2.執行redis命令:redisCommand
void *redisCommand(redisContext
*c
, const char *format
...)
- 函數解釋
- 該函數用于執行redis數據庫中的命令,第一個參數為連接數據庫返回的redisContext,剩下的參數為變參,如同C語言中的prinf()函數。
- 此函數的返回值為void*,但是一般會強制轉換為redisReply類型,以便做進一步的處理。
- 使用案例
首先介紹的是 redisCommand。此函數采用類似于printf的格式。最簡單的形式是這樣使用:
reply
= redisCommand(context
, "SET foo bar");說明
%s符在命令中插入一個字符串,并用于strlen確定字符串的長度:
reply
= redisCommand(context
, "SET foo %s", value
);當您需要在命令中傳遞二進制安全字符串時,
%b可以使用說明符。與指向字符串
的指針一起,它需要字符串的size_tlength參數:
reply
= redisCommand(context
, "SET foo %b", value
, (size_t
) valuelen
);在內部,Hiredis將命令拆分為不同的參數,并將其轉換為用于與Redis通信
的協議。一個或多個空格分隔參數,因此您可以在參數的任何位置使用說明符:
reply
= redisCommand(context
, "SET key:%s %s", myid
, value
);
void * redisCommandArgv(redisContext
* c,
int argc,
const char ** argv,
const size_t
* argvlen)
;
- 函數解釋
- 它需要參數的數量,argc字符串數組argv和參數的長度argvlen。
- 為了方便起見,argvlen可以將設置為NULL,并且函數將strlen(3)在每個參數上使用以確定其長度。
- 顯然,當任何一個參數需要二進制安全時,argvlen都應提供整個長度數組。
- 返回值的語義與相同redisCommand。
3.釋放redisCommand
void freeReplyObject(void *reply
)
- 函數解釋
- 釋放redisCommand執行后返回的的redisReply所占用的內存。
- redisCommand成功執行命令后,的返回值將保留答復。
- 發生錯誤時,返回值為NULL并且err將設置上下文中的字段。返回錯誤后,上下文context將無法重用,您應該建立一個新的連接。
- 該標準回答說redisCommand是的類型redisReply。中的 type字段redisReply應用于測試收到的回復類型:
- REDIS_REPLY_STATUS:
該命令回復了狀態回復。可以使用訪問狀態字符串reply->str。可以使用訪問此字符串的長度reply->len。
- REDIS_REPLY_ERROR:
- 該命令回答了一個錯誤。錯誤字符串的訪問方式與相同
- REDIS_REPLY_INTEGER:
- 該命令以整數回答。可以使用reply->integer類型的字段訪問整數值 long long。
- REDIS_REPLY_NIL:
- 該命令回復了一個nil對象。沒有數據可訪問。
- REDIS_REPLY_STRING:
- 大量(字符串)回復。可以使用來訪問回復的值reply->str。可以使用訪問此字符串的長度reply->len。
- REDIS_REPLY_ARRAY:
- 多批量回復。多批量答復中的元素數存儲在中 reply->elements。
- 多批量回復中的每個元素也是一個redisReply對象,可以通過訪問reply->element[..index..]。
應該使用freeReplyObject()函數釋放答復。請注意,此函數將負責釋放數組和嵌套數組中包含的子答復對象,因此用戶無需釋放子答復(這實際上是有害的,并且會破壞內存)。
4.斷開連接:redisFree
void redisFree(redisContext
*c
)
- 此函數立即關閉套接字,然后釋放在創建上下文時完成的分配。
5.流水線:Pipelining
為了解釋Hiredis如何支持阻塞連接中的流水線操作,需要了解內部執行流程。
- redisCommand調用該系列中的任何功能時,Hiredis首先根據Redis協議格式化命令。
- 然后將格式化的命令放入上下文的輸出緩沖區中。此輸出緩沖區是動態的,因此它可以容納任意數量的命令。
- 將命令放入輸出緩沖區后,將redisGetReply被調用。該函數具有以下兩個執行路徑:
- 輸入緩沖區為非空:
- 嘗試解析來自輸入緩沖區的單個答復并返回
- 如果無法解析任何答復,請繼續執行2
- 輸入緩沖區為空:
- 將整個輸出緩沖區寫入套接字
- 從套接字讀取,直到可以解析單個答復
- 該函數redisGetReply作為Hiredis API的一部分導出,可以在套接字上收到期望的答復時使用。
- 對于管道命令,唯一需要做的就是填充輸出緩沖區。為此redisCommand,除了不返回答復外,可以使用與該系列相同的兩個命令:
void redisAppendCommand(redisContext
* c,
const char * format,
...)
;
void redisAppendCommandArgv(redisContext
* c,
int argc,
const char ** argv,
const size_t
* argvlen)
;
- 一次或多次調用函數后,redisGetReply可用于接收后續答復。
- 此函數的返回值是REDIS_OK或REDIS_ERR,其中后者表示讀取答復時發生錯誤。就像其他命令一樣,err上下文中的字段可用于找出導致此錯誤的原因。
- 以下示例顯示了一個簡單的管道(僅導致對的單個調用write(2)和對的單個調用read(2)):
redisReply
*reply
;
redisAppendCommand(context
,"SET foo bar");
redisAppendCommand(context
,"GET foo");redisGetReply(context
,(void *)&reply
);
freeReplyObject(reply
);
redisGetReply(context
,(void *)&reply
); freeReplyObject(reply
);
reply
= redisCommand(context
,"SUBSCRIBE foo");
freeReplyObject(reply
);while(redisGetReply(context
,(void *)&reply
) == REDIS_OK
)
{freeReplyObject(reply
);
}
更多用法請點擊:https://github.com/redis/hiredis
三、簡單封裝hiredis
#ifndef __REDIS_HANDLER_H__
#define __REDIS_HANDLER_H__#include <hiredis/hiredis.h>
#include <string>using namespace std
;enum
{M_REDIS_OK
= 0, M_CONNECT_FAIL
= -1, M_CONTEXT_ERROR
= -2, M_REPLY_ERROR
= -3, M_EXE_COMMAND_ERROR
= -4
};class RedisHandler
{
public:RedisHandler();~RedisHandler();int connect(const string
&addr
, int port
, const string
&pwd
= ""); int disConnect(); int setValue(const string
&key
, const string
&value
); int getValue(const string
&key
, string
&value
); int delKey(const string
&key
); int printAll(); string
getErrorMsg();
private:string m_addr
; int m_port
; string m_pwd
; redisContext
* pm_rct
; redisReply
* pm_rr
; string error_msg
; int connectAuth(const string
&pwd
); int handleReply(void* value
= NULL, redisReply
***array
= NULL);
};#endif
#include "redis_handler.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std
;RedisHandler
::RedisHandler()
{m_addr
= "";m_port
= 0;m_pwd
= "";pm_rct
= NULL;pm_rr
= NULL;error_msg
= "";
}RedisHandler
::~RedisHandler()
{disConnect();pm_rct
= NULL;pm_rr
= NULL;
}
int RedisHandler
::connect(const string
&addr
= "127.0.0.1", int port
= 6379, const string
&pwd
) {m_addr
= addr
;m_port
= port
;m_pwd
= pwd
;pm_rct
= redisConnect(m_addr
.c_str(), m_port
);if (pm_rct
->err
){error_msg
= pm_rct
->errstr
;return M_CONNECT_FAIL
;}if (!m_pwd
.empty()){return connectAuth(m_pwd
);}return M_REDIS_OK
;
}
int RedisHandler
::disConnect()
{redisFree(pm_rct
);freeReplyObject(pm_rr
);
}
int RedisHandler
::setValue(const string
&key
, const string
&value
)
{string cmd
= "set " + key
+ " " + value
;pm_rr
= (redisReply
*)redisCommand(pm_rct
, cmd
.c_str());return handleReply();
}
int RedisHandler
::getValue(const string
&key
, string
&value
)
{string cmd
= "get " + key
;pm_rr
= (redisReply
*)redisCommand(pm_rct
, cmd
.c_str());int ret
= handleReply(&value
);
}
int RedisHandler
::delKey(const string
&key
)
{string cmd
= "del " + key
;pm_rr
= (redisReply
*)redisCommand(pm_rct
, cmd
.c_str());int rows
= 0;int ret
= handleReply(&rows
);if (ret
== M_REDIS_OK
)return rows
;elsereturn ret
;
}
int RedisHandler
::printAll()
{string cmd
= "keys *";pm_rr
= (redisReply
*)redisCommand(pm_rct
, cmd
.c_str());int len
;redisReply
**array
;int ret
= handleReply(&len
, &array
);if (ret
== M_REDIS_OK
){for (int i
= 0; i
< len
; i
++)cout
<< string(array
[i
]->str
) << endl
;}elsereturn 0;
}
string RedisHandler
::getErrorMsg()
{return error_msg
;
}
int RedisHandler
::connectAuth(const string
&psw
)
{string cmd
= "auth " + psw
;pm_rr
= (redisReply
*)redisCommand(pm_rct
, cmd
.c_str());return handleReply();
}
int RedisHandler
::handleReply(void* value
, redisReply
*** array
)
{if (pm_rct
->err
){error_msg
= pm_rct
->errstr
;return M_CONTEXT_ERROR
;}if (pm_rr
== NULL){error_msg
= "auth redisReply is NULL";return M_REPLY_ERROR
;}switch (pm_rr
->type
){case REDIS_REPLY_ERROR
:error_msg
= pm_rr
->str
;return M_EXE_COMMAND_ERROR
;case REDIS_REPLY_STATUS
:if (!strcmp(pm_rr
->str
, "OK"))return M_REDIS_OK
;else{error_msg
= pm_rr
->str
;return M_EXE_COMMAND_ERROR
;}case REDIS_REPLY_INTEGER
:*(int*)value
= pm_rr
->integer
;return M_REDIS_OK
;case REDIS_REPLY_STRING
:*(string
*)value
= pm_rr
->str
;return M_REDIS_OK
;case REDIS_REPLY_NIL
:*(string
*)value
= "";return M_REDIS_OK
;case REDIS_REPLY_ARRAY
:*(int*)value
= pm_rr
->elements
;*array
= pm_rr
->element
;return M_REDIS_OK
;default:error_msg
= "unknow reply type";return M_EXE_COMMAND_ERROR
;}
}
#include <iostream>
#include <string>
#include "redis_handler.h"
using namespace std
;int main()
{RedisHandler
* rh
= new RedisHandler();int ret
;cout
<< "錯誤測試: " << "地址錯誤" << endl
;ret
= rh
->connect("34.15.14.15", 6379, "linesum");if (ret
!= M_REDIS_OK
)cout
<< "redis error: " << rh
->getErrorMsg() << endl
;cout
<< "錯誤測試: " << "端口錯誤" << endl
;ret
= rh
->connect("127.0.0.1", 1234, "linesum");if (ret
!= M_REDIS_OK
)cout
<< "redis error: " << rh
->getErrorMsg() << endl
;cout
<< "錯誤測試: " << "密碼錯誤" << endl
;ret
= rh
->connect("127.0.0.1", 6479, "linsum");if (ret
!= M_REDIS_OK
)cout
<< "redis error: " << rh
->getErrorMsg() << endl
;ret
= rh
->connect("127.0.0.1", 6479, "linesum");if (ret
!= M_REDIS_OK
){cout
<< "redis error: " << rh
->getErrorMsg() << endl
;return ret
;}cout
<< "錯誤測試: " << "set不帶value參數" << endl
;ret
= rh
->setValue("key11", "");if (ret
!= M_REDIS_OK
)cout
<< "redis error: " << rh
->getErrorMsg() << endl
;ret
= rh
->setValue("key11", "value11");if (ret
!= M_REDIS_OK
){cout
<< "redis error: " << rh
->getErrorMsg() << endl
;return ret
;}ret
= rh
->setValue("key22", "value22");if (ret
!= M_REDIS_OK
){cout
<< "redis error: " << rh
->getErrorMsg() << endl
;return ret
;}string str
;cout
<< "錯誤測試: " << "get不帶key參數" << endl
;ret
= rh
->getValue("key1111", str
);if (ret
!= M_REDIS_OK
)cout
<< "redis error: " << rh
->getErrorMsg() << endl
;ret
= rh
->getValue("key11", str
);if (ret
!= M_REDIS_OK
){cout
<< "redis error: " << rh
->getErrorMsg() << endl
;return ret
;}elsecout
<< "value : " << str
<< endl
;ret
= rh
->printAll();if (ret
!= M_REDIS_OK
){cout
<< "redis error: " << rh
->getErrorMsg() << endl
;return ret
;}cout
<< "錯誤測試: " << "刪除不存在的key" << endl
;ret
= rh
->delKey("key1111");if (ret
!= M_REDIS_OK
)cout
<< "redis error: " << rh
->getErrorMsg() << endl
;ret
= rh
->delKey("key11");if (ret
!= M_REDIS_OK
){cout
<< "redis error: " << rh
->getErrorMsg() << endl
;return ret
;}delete rh
;return 0;
}
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生
總結
以上是生活随笔為你收集整理的Linux下使用C++操作redis数据库的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。