日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下使用C++操作redis数据库

發布時間:2024/4/11 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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環境使用。

  • 下載hiredis.h

  • hiredis.h 的下載地址為:https://github.com/redis/hiredis

  • 配置環境變量

  • git clone完hiredis.h后,進入hiredis目錄當中

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);// handle error} 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); // reply for SET freeReplyObject(reply); redisGetReply(context,(void *)&reply); // reply for GETfreeReplyObject(reply);
  • 此API也可以用于實現阻塞:
reply = redisCommand(context,"SUBSCRIBE foo"); freeReplyObject(reply);while(redisGetReply(context,(void *)&reply) == REDIS_OK) {// consume messagefreeReplyObject(reply); }

更多用法請點擊:https://github.com/redis/hiredis

三、簡單封裝hiredis

  • redis_handler.h
#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, //連接redis失敗M_CONTEXT_ERROR = -2, //RedisContext返回錯誤M_REPLY_ERROR = -3, //redisReply錯誤M_EXE_COMMAND_ERROR = -4 //redis命令執行錯誤 };class RedisHandler { public:RedisHandler();~RedisHandler();int connect(const string &addr, int port, const string &pwd = ""); //連接redis數據庫:addr:IP地址,port:端口號,pwd:密碼(默認為空)int disConnect(); //斷開連接int setValue(const string &key, const string &value); //添加或修改鍵值對,成功返回0,失敗<0int getValue(const string &key, string &value); //獲取鍵對應的值,成功返回0,失敗<0int delKey(const string &key); //刪除鍵,成功返回影響的行數,失敗<0int printAll(); //打印所有的鍵值對string getErrorMsg(); //獲取錯誤信息 private:string m_addr; //IP地址int m_port; //端口號string m_pwd; //密碼redisContext* pm_rct; //redis結構體redisReply* pm_rr; //返回結構體string error_msg; //錯誤信息int connectAuth(const string &pwd); //使用密碼登錄int handleReply(void* value = NULL, redisReply ***array = NULL); //處理返回的結果 };#endif
  • redis_handler.cpp
#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; }/* 連接redis數據庫 addr: 地址,port:端口號,pwd:密碼 成功返回M_REDIS_OK,失敗返回M_CONNECT_FAIL */ 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; }/* 斷開redis連接 */ int RedisHandler::disConnect() {redisFree(pm_rct);freeReplyObject(pm_rr); }/* 添加或插入鍵值對 key:鍵,value:值 成功返回M_REDIS_OK,失敗返回<0 */ 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(); }/* 獲取鍵對應的值 key:鍵,value:值引用 成功返回M_REDIS_OK,失敗返回<0 */ 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); }/* 刪除鍵 key:鍵 成功返回影響的行數(可能為0),失敗返回<0 */ 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; }/* 使用密碼登錄 psw:登錄密碼 成功返回M_REDIS_OK,失敗返回<0 */ int RedisHandler::connectAuth(const string &psw) {string cmd = "auth " + psw;pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());return handleReply(); }/* 處理redis返回的信息 value:數據指針,用于保存redis返回的基本類型(value指針指向該數據) array:數組指針,用于保存redis返回的數組 成功返回M_REDIS_OK,失敗返回<0 */ 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;} }
  • main.cpp
#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;}//set測試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;}//get測試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;//print測試ret = rh->printAll();if (ret != M_REDIS_OK){cout << "redis error: " << rh->getErrorMsg() << endl;return ret;}//del測試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数据库的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。