Linux下的c/c++開發之操作Redis數據庫

C/C++ 操作 Redis 的常用庫

在 C/C++ 開發中操作 Redis 有多種方式,最主流的選擇是使用第三方客戶端庫。由于 Redis 官方本身是使用 C 編寫的,提供的 API 非常適合 C/C++ 調用。常見的 Redis C/C++ 客戶端庫包括:

  • hiredis:官方推薦的輕量級 C 客戶端。

  • hiredis-vip:支持 Redis Cluster 的增強版 hiredis。

  • redis-plus-plus:基于 hiredis 的現代 C++ 封裝,使用更簡潔直觀。

hiredis 簡介(官方推薦,輕量高效)

hiredis 是 Redis 官方維護的 C 語言客戶端庫,專注于提供最基本的 Redis 通信支持。它設計簡潔,僅包含:

  • 同步命令發送與接收

  • 簡單的異步接口(需配合 libevent、libev 使用)

  • 輕量高效、易于嵌入項目中

核心特性

  • 同步與異步 API 支持

  • 占用內存小,編譯快速

  • 無多余封裝,緊貼 Redis 協議

  • 社區活躍,文檔簡潔

hiredis-vip 簡介(支持 Redis Cluster)

hiredis-vip 是在 hiredis 基礎上增強的版本,專門用于支持 Redis Cluster 的自動分片與節點路由功能。它由開源社區維護,并兼容 hiredis 的接口風格。

核心特性

  • 支持 Redis Cluster 的自動路由與重定向處理

  • 封裝了 key-slot 映射、MOVED/ASK 重試等邏輯

  • 同樣提供同步和異步模式

  • 提供 redisClusterContext 和集群級命令發送接口

redis-plus-plus(又名 sw::redis++)是基于 hiredis 的現代 C++ 封裝庫,由中國開發者 swz30 編寫。它使用 STL 風格設計,提供 RAII、異常處理、泛型接口,更符合現代 C++ 開發習慣。

核心特性

  • 提供類模板支持多種數據類型(如 std::string, std::vector

  • 支持連接池、管道(pipeline)、事務(transaction)

  • 封裝 cluster 支持(底層依賴 hiredis-vip)

  • 易用且文檔完善,適合快速上手

該篇文章主要介紹hiredis-vip的安裝和使用

hiredis-vip的安裝

必要依賴

hiredis-vip 依賴官方 hiredis 作為底層 Redis 通信庫,因此需要先安裝 hiredis

git clone https://github.com/redis/hiredis.git
cd hiredis
make
sudo make install

從github拉取源碼編譯安裝hiredis-vip

git clone https://github.com/vipshop/hiredis-vip.git
cd hiredis-vip
make
sudo make install

安裝后我們會得到:

①靜態庫文件:/usr/local/lib/libhiredis-vip.a? ?這是你在 C/C++ 項目中需要鏈接的庫。

②頭文件:

頭文件路徑主要功能描述提供的核心類型/函數使用場景是否必需
<hiredis-vip/hiredis.h>單機版 Redis 客戶端接口(繼承自官方 hiredis)redisContextredisConnect()redisCommand()單個 Redis 實例(非集群)若用單機模式需要
<hiredis-vip/hircluster.h>Redis Cluster 操作的核心接口redisClusterContextredisClusterCommand()分布式 Redis 集群通信集群操作需要
<hiredis-vip/adapters/libevent.h>異步 Redis Cluster 支持,綁定到 libevent 事件循環redisClusterLibeventAttach()異步事件驅動開發(libevent)僅異步需要

<hiredis.h>介紹

結構體redisContext

用于連接上下文

struct redisContext {int fd;                  // 套接字描述符int flags;               // 狀態標志char *errstr;            // 錯誤描述字符串int err;                 // 錯誤碼void *reader;            // 協議解析器
};

結構體redisReply

所有 Redis 響應的封裝結構體

typedef struct redisReply {int type;                   // 響應類型,對應 REDIS_REPLY_* 枚舉(如 REDIS_REPLY_STRING, REDIS_REPLY_INTEGER 等)long long integer;          // 如果 type == REDIS_REPLY_INTEGER,則該字段表示返回的整數值int len;                    // 如果 type == REDIS_REPLY_STRING 或 REDIS_REPLY_STATUS 或 REDIS_REPLY_ERROR,則該字段表示 str 的長度(不包含 '\0')char *str;                  // // - 當 type == REDIS_REPLY_STRING 時,str 指向字符串值// - 當 type == REDIS_REPLY_ERROR 時,str 是錯誤信息// - 當 type == REDIS_REPLY_STATUS 時,str 是狀態信息(如 "OK")// - 其他類型該字段為 NULLsize_t elements;            // 如果 type == REDIS_REPLY_ARRAY,則表示數組中的元素數量struct redisReply **element; // // - 當 type == REDIS_REPLY_ARRAY 時,該字段指向一個 redisReply* 數組,//   每個元素是數組中的一個返回項(可遞歸地是另一個 redisReply)// - 其他類型該字段為 NULL
} redisReply;

結構體?redisAsyncContext

用于表示一個異步 Redis 客戶端上下文

typedef struct redisAsyncContext {redisContext c;         // 內部使用的同步上下文(基礎連接信息)int err;                // 錯誤碼char errstr[128];       // 錯誤信息字符串void *data;             // 用戶數據...
} redisAsyncContext;

redisReply中的類型枚舉值

#define REDIS_REPLY_STRING 1
#define REDIS_REPLY_ARRAY 2
#define REDIS_REPLY_INTEGER 3
#define REDIS_REPLY_NIL 4
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6
含義
REDIS_REPLY_STRING字符串類型
REDIS_REPLY_ARRAY數組結果(如 KEYS *
REDIS_REPLY_INTEGER整數類型(如 INCR 結果)
REDIS_REPLY_NIL空值(如不存在的 key)
REDIS_REPLY_STATUS狀態,如 "OK"
REDIS_REPLY_ERROR錯誤

API

①redisConnect

連接 Redis 服務器

redisContext *redisConnect(const char *ip, int port);
  • ip:Redis 服務器 IP 地址,如 "127.0.0.1"

  • port:端口號,如 6379

  • 返回:成功返回 redisContext*,失敗 err 字段非零,errstr 描述錯誤。

②redisConnectWithTimeout

帶超時設置的連接方式

redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);

tv:超時時間(秒+微秒),如 {1, 500000} 表示 1.5 秒。

③redisFree

釋放連接資源

void redisFree(redisContext *c);

參數:Redis 連接上下文。

④redisCommand

發送命令并同步獲取結果

void *redisCommand(redisContext *c, const char *format, ...);
  • format:格式化字符串,如 "SET key %s""INCR %s"

  • 可變參數:要插入的 key、value 等。

  • 返回:指向 redisReply 的指針,需使用 freeReplyObject 釋放。

redisReply *reply = (redisReply *)redisCommand(c, "SET %s %s", "mykey", "hello");
⑤freeReplyObject

釋放 redisReply 內存

void freeReplyObject(void *reply);
⑥redisCommandArgv

使用參數數組方式發送命令

void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
  • argc:參數數量;

  • argv:參數數組;

  • argvlen:每個參數的長度數組;

  • 返回:redisReply*

const char *set_argv[] = {"SET", "mykey", "hello"};
size_t set_argvlen[] = {3, 5, 5};  // 每個參數的長度
redisReply *reply = (redisReply *)redisCommandArgv(c, 3, set_argv, set_argvlen);

示例:

#include <iostream>
#include <string>
#include <hiredis-vip/hiredis.h>int main() {// 1. 創建連接redisContext* c = redisConnect("127.0.0.1", 6379);if (c == nullptr || c->err) {std::cerr << "Connection error: " << (c ? c->errstr : "NULL") << std::endl;return -1;}// 2. 使用 redisCommand 發送 SET 命令redisReply* reply = (redisReply*)redisCommand(c, "SET %s %s", "foo", "123");if (reply && reply->type == REDIS_REPLY_STATUS) {std::cout << "SET result: " << reply->str << std::endl;}freeReplyObject(reply);// 3. 使用 redisCommand 發送 GET 命令reply = (redisReply*)redisCommand(c, "GET %s", "foo");if (reply && reply->type == REDIS_REPLY_STRING) {std::cout << "GET result: " << reply->str << std::endl;}freeReplyObject(reply);// 4. 使用 redisCommandArgv 發送 DEL 命令const char* argv[] = {"DEL", "foo"};size_t argvlen[] = {3, 3};reply = (redisReply*)redisCommandArgv(c, 2, argv, argvlen);if (reply && reply->type == REDIS_REPLY_INTEGER) {std::cout << "DEL result: " << reply->integer << std::endl;}freeReplyObject(reply);// 5. 釋放連接redisFree(c);return 0;
}

⑦異步相關api

函數原型函數作用函數參數返回值
redisClusterAsyncConnect(const char *startup_nodes, int flags)異步連接 Redis Cluster- startup_nodes:Redis Cluster 節點的啟動地址列表,格式如 "127.0.0.1:7000"。 - flags:連接選項標志。返回 redisClusterAsyncContext*,表示異步上下文。
redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn)設置連接成功的回調函數- acc:異步上下文。 - fn:連接成功回調函數,參數為 redisClusterAsyncContext* accredisContext* c無返回值
redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn)設置連接斷開的回調函數- acc:異步上下文。 - fn:斷開連接回調函數,參數為 redisClusterAsyncContext* accredisContext* c無返回值
redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisCallbackFn *fn, void *privdata, const char *format, ...)異步發送格式化命令- acc:異步上下文。 - fn:命令執行完后的回調函數,參數為 redisClusterAsyncContext* accredisReply* r。 - privdata:回調函數的用戶數據。 - format:命令的格式化字符串。返回 void*,通常傳入回調函數。
redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen)異步參數數組方式發送命令- acc:異步上下文。 - fn:命令執行完后的回調函數,參數為 redisClusterAsyncContext* accredisReply* r。 - privdata:回調函數的用戶數據。 - argc:參數數量。 - argv:命令的參數數組。 - argvlen:每個參數的長度。返回 void*,通常傳入回調函數。
redisClusterLibeventAttach(redisClusterAsyncContext *acc, struct event_base *base)將異步 Redis Cluster 上下文綁定到 libevent- acc:異步上下文。 - base:libevent 事件循環的基礎對象。返回 int,成功為 0,失敗為 -1。
redisClusterAsyncFree(redisClusterAsyncContext *acc)釋放異步上下文- acc:異步上下文。無返回值

示例:

#include <iostream>
#include <hiredis-vip/hircluster.h>
#include <event.h>
#include <cstring>// 連接成功的回調
void connectCallback(redisClusterAsyncContext *acc, redisContext *c) {std::cout << "Connected to Redis Cluster!" << std::endl;
}// 斷開連接的回調
void disconnectCallback(redisClusterAsyncContext *acc, redisContext *c) {std::cout << "Disconnected from Redis Cluster!" << std::endl;
}// 異步命令的回調
void commandCallback(redisClusterAsyncContext *acc, redisReply *reply) {if (reply->type == REDIS_REPLY_STRING) {std::cout << "Reply: " << reply->str << std::endl;} else if (reply->type == REDIS_REPLY_STATUS) {std::cout << "Status: " << reply->str << std::endl;} else {std::cout << "Received unexpected reply type" << std::endl;}freeReplyObject(reply);
}int main() {// 創建 libevent 事件基礎對象struct event_base *base = event_base_new();if (!base) {std::cerr << "Unable to create event base!" << std::endl;return -1;}// 異步連接 Redis ClusterredisClusterAsyncContext *acc = redisClusterAsyncConnect("127.0.0.1:7000", 0);if (acc == NULL || acc->err) {std::cerr << "Connection error: " << (acc ? acc->errstr : "NULL") << std::endl;return -1;}// 設置連接和斷開回調redisClusterAsyncSetConnectCallback(acc, connectCallback);redisClusterAsyncSetDisconnectCallback(acc, disconnectCallback);// 將異步上下文與 libevent 綁定if (redisClusterLibeventAttach(acc, base) != 0) {std::cerr << "Failed to attach to libevent!" << std::endl;redisClusterAsyncFree(acc);event_base_free(base);return -1;}// 發送 SET 命令redisClusterAsyncCommand(acc, commandCallback, NULL, "SET %s %s", "foo", "bar");// 發送 GET 命令redisClusterAsyncCommand(acc, commandCallback, NULL, "GET %s", "foo");// 發送帶有參數數組的命令(例如 MSET)const char *argv[] = {"MSET", "foo", "bar", "baz", "qux"};size_t argvlen[] = {4, 3, 3, 3, 3};redisClusterAsyncCommandArgv(acc, commandCallback, NULL, 5, argv, argvlen);// 運行事件循環,等待命令執行event_base_dispatch(base);// 釋放資源redisClusterAsyncFree(acc);event_base_free(base);return 0;
}

<hircluster.h>介紹

結構體redisClusterContext

  • redisClusterContext 是整個 Redis 集群交互的核心結構,管理了集群拓撲(節點和 slot 映射)、連接信息、重定向機制等。

  • 使用該結構的 API(如 redisClusterCommand)時,內部會根據 key 自動決定使用哪個節點連接并完成請求。

typedef struct redisClusterContext {int err;                     // 錯誤碼,0 表示無錯誤,非 0 表示出錯char errstr[128];            // 錯誤信息字符串,用于描述出錯原因int flags;                   // 標志位,預留擴展,如是否啟用 pipeline 等// 當前操作所使用的連接節點信息redisContext *con;           // 當前正在使用的 hiredis 連接上下文(非集群結構,但內部已支持)char *cmd;                   // 上一次執行的命令字符串副本(用于調試或日志)struct dict *nodes;          // 所有節點信息(key 為 ip:port,value 為 node 對象)struct dict *slots;          // slot 到節點的映射表(0-16383)struct list *requests;       // pipeline 請求列表(若使用 pipeline 模式)struct timeval *timeout;     // 連接超時設置char *err_code;              // 附加的 Redis 錯誤碼字符串(如 MOVED, ASK)..........
} redisClusterContext;

結構體redisClusterAsyncContext

相比普通 Redis,異步集群客戶端使用 redisClusterAsyncContext

typedef struct redisClusterAsyncContext {redisClusterContext *cc;    // 關聯的集群上下文void *data;...
} redisClusterAsyncContext;

API

①redisClusterConnect

創建一個 Redis Cluster 上下文并初始化連接信息。

redisClusterContext *redisClusterConnect(const char *nodes, int flags);

參數:

  • nodes:Redis 節點地址字符串,如 "127.0.0.1:7000,127.0.0.1:7001",支持多個地址。

  • flags:連接選項,目前應傳 0,為保留字段。

返回值

  • 成功返回 redisClusterContext*

  • 失敗返回 NULL,可通過 cc->errcc->errstr 獲取錯誤信息。

②redisClusterSetOptionAddNode

動態添加一個集群節點地址到上下文中,適用于構建連接前動態配置節點。

"動態添加" 指的是在Redis 集群連接已經創建并且正在使用的過程中,后續可以增加新的節點地址到已經存在的 redisClusterContext 中,而無需重新創建或重新連接整個集群。

int redisClusterSetOptionConnectTimeout(redisClusterContext *cc, const struct timeval tv);

參數

  • cc:Redis 集群上下文

  • addr:如 "127.0.0.1:7002"

返回值

  • 成功返回 0,失敗返回 -1

③redisClusterSetOptionConnectTimeout

設置連接超時時間。

int redisClusterSetOptionConnectTimeout(redisClusterContext *cc, const struct timeval tv);

參數

  • cc:Redis 集群上下文

  • tvstruct timeval 結構體,單位為秒和微秒(例如 {2, 0} 表示 2 秒)

返回值

  • 成功返回 0,失敗返回 -1

處該設置外,其他常用設置有:

函數名稱函數原型作用說明
設置連接超時時間int redisClusterSetOptionConnectTimeout(redisClusterContext *cc, struct timeval tv);設置連接 Redis 節點的最大時間,超過即失敗(單位:秒+微秒)
設置操作超時時間int redisClusterSetOptionTimeout(redisClusterContext *cc, struct timeval tv);設置執行 Redis 命令的超時時間
設置讀取響應超時時間int redisClusterSetOptionReadTimeout(redisClusterContext *cc, struct timeval tv);設置等待 Redis 響應數據的最大時間
設置最大重試次數int redisClusterSetOptionMaxRetries(redisClusterContext *cc, int max_retries);出現網絡/重定向等錯誤時最大重試次數
設置最大重定向次數int redisClusterSetOptionMaxRedirects(redisClusterContext *cc, int max_redirects);設置因 Moved/Ask 錯誤進行的最多重定向次數
設置錯誤處理策略int redisClusterSetOptionErrHandling(redisClusterContext *cc, int on_error);設置遇到錯誤時的處理策略(重試/中斷等)
設置認證密碼int redisClusterSetOptionPassword(redisClusterContext *cc, const char *password);設置連接 Redis 節點的密碼(適用于集群開啟密碼認證的情況)
啟用 SSL 加密int redisClusterSetOptionSsl(redisClusterContext *cc, int ssl_flag);設置是否使用 SSL 連接 Redis(1 開啟,0 關閉)
添加初始節點地址int redisClusterSetOptionAddNode(redisClusterContext *cc, const char *ipport);添加用于初始化連接的節點地址,支持多個
④redisClusterConnect2

實際建立 Redis Cluster 的連接,必須在設置完選項后調用。

int redisClusterConnect2(redisClusterContext *cc);

返回值

  • 成功返回 0,失敗返回 -1

⑤redisClusterCommand

向 Redis Cluster 發送格式化命令(如 SET %s %s),自動路由到正確的節點。

在 Redis Cluster 模式中,所有的鍵(key)會被映射到 0~16383 共 16384 個槽(slots)中,每個槽再由集群中的某個節點負責。例如:

  • 節點 A 管理 slot 0~5460

  • 節點 B 管理 slot 5461~10922

  • 節點 C 管理 slot 10923~16383

當你執行命令 SET mykey 123 時:

  • Redis 會對 mykey 做 CRC16 哈希并對 16384 取模,得到一個 slot 編號(例如 slot 9181

  • 然后 Redis Cluster 會根據 slot 映射表,找到哪個節點負責這個 slot

  • 然后把命令發送到對應的節點去執行

hiredis-vip 如何“自動路由”?

hiredis-vip 提供了 redisClusterCommand() 函數,它會:

  1. 自動對 key 做哈希并映射到 slot

  2. 根據 slot,查找當前負責這個 slot 的節點

  3. 自動建立連接(或復用已有連接)并將命令發送給這個節點

  4. 返回對應的 redisReply* 給你,無需你關心命令該發給哪個 IP/端口

你只需寫:

redisClusterCommand(cc, "SET %s %s", "mykey", "hello");

hiredis-vip 會自動完成這些步驟,無需你手動計算哈希、選節點。

⑥redisClusterCommandArgv

以參數數組形式向 Redis Cluster 發送命令,適用于包含二進制數據的場景。

void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen);

參數

  • cc:Redis 集群上下文

  • argc:參數個數

  • argv:參數數組,如 {"SET", "key", "value"}

  • argvlen:每個參數的長度數組

返回值

  • 返回 redisReply* 指針,需手動 freeReplyObject() 釋放

⑦redisClusterFree

釋放上下文資源,避免內存泄露。

void redisClusterFree(redisClusterContext *cc);
⑧redisClusterReset

重置上下文信息,清空連接和緩存,用于恢復連接失敗后的重建。

void redisClusterReset(redisClusterContext *cc);

redis連接的兩種方式:

方式一:簡潔連接(推薦,自動 connect)

redisClusterContext *cc = redisClusterConnect("127.0.0.1:7000", 0);

這個函數會:

  • 創建 redisClusterContext

  • 設置初始節點列表

  • 自動調用 redisClusterConnect2() 進行實際連接

所以:如果你用了 redisClusterConnect(),就不需要自己手動調用 redisClusterConnect2()

方式二:手動配置 + 顯式連接

這種方式適用于你需要更精細控制連接參數的場景:

redisClusterContext *cc = redisClusterContextInit();  // 只創建上下文
redisClusterSetOptionAddNodes(cc, "127.0.0.1:7000");  // 添加節點
redisClusterSetOptionConnectTimeout(cc, timeout);     // 設置連接超時等選項
redisClusterConnect2(cc);                             // 必須手動調用連接

在使用 redisClusterContextInit() + 設置選項方式時,你必須手動調用 redisClusterConnect2(),否則上下文未建立連接,后續命令會失敗。

?示例:

⑨異步相關api
函數原型功能說明函數參數返回值
redisClusterAsyncConnect(const char *startup_nodes, int flags)異步連接 Redis Cluster- startup_nodes:Redis Cluster 節點的啟動地址列表,格式如 "127.0.0.1:7000"。 - flags:連接選項標志。返回 redisClusterAsyncContext*,表示異步上下文。
redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn)設置連接成功的回調函數- acc:異步上下文。 - fn:連接成功回調函數,參數為 redisClusterAsyncContext* accredisContext* c無返回值
redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn)設置連接斷開的回調函數- acc:異步上下文。 - fn:斷開連接回調函數,參數為 redisClusterAsyncContext* accredisContext* c無返回值
redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisCallbackFn *fn, void *privdata, const char *format, ...)異步發送格式化命令- acc:異步上下文。 - fn:命令執行完后的回調函數,參數為 redisClusterAsyncContext* accredisReply* r。 - privdata:回調函數的用戶數據。 - format:命令的格式化字符串。返回 void*,通常傳入回調函數。
redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen)異步參數數組方式發送命令- acc:異步上下文。 - fn:命令執行完后的回調函數,參數為 redisClusterAsyncContext* accredisReply* r。 - privdata:回調函數的用戶數據。 - argc:參數數量。 - argv:命令的參數數組。 - argvlen:每個參數的長度。返回 void*,通常傳入回調函數。
redisClusterLibeventAttach(redisClusterAsyncContext *acc, struct event_base *base)將異步 Redis Cluster 上下文綁定到 libevent- acc:異步上下文。 - base:libevent 事件循環的基礎對象。返回 int,成功為 0,失敗為 -1。
redisClusterAsyncFree(redisClusterAsyncContext *acc)釋放異步上下文- acc:異步上下文。無返回值

示例:

#include <iostream>
#include <hiredis-vip/hircluster.h>
#include <event2/event.h>// 回調函數:連接成功
void connectCallback(redisClusterAsyncContext *acc, redisContext *c) {std::cout << "Connected to Redis Cluster!" << std::endl;
}// 回調函數:連接斷開
void disconnectCallback(redisClusterAsyncContext *acc, redisContext *c) {std::cout << "Disconnected from Redis Cluster." << std::endl;
}// 回調函數:命令響應
void commandCallback(redisClusterAsyncContext *acc, redisReply *r) {if (r != NULL) {std::cout << "Command reply: " << r->str << std::endl;} else {std::cout << "Command failed" << std::endl;}
}// 主函數
int main() {// 初始化 libevent 事件循環struct event_base *base = event_base_new();if (!base) {std::cerr << "Could not initialize libevent!" << std::endl;return -1;}// 異步連接 Redis Clusterconst char *startup_nodes = "127.0.0.1:7000,127.0.0.1:7001";redisClusterAsyncContext *acc = redisClusterAsyncConnect(startup_nodes, 0);if (acc == NULL || acc->err) {std::cerr << "Connection error: " << (acc ? acc->errstr : "NULL") << std::endl;event_base_free(base);return -1;}// 設置連接成功的回調redisClusterAsyncSetConnectCallback(acc, connectCallback);// 設置連接斷開的回調redisClusterAsyncSetDisconnectCallback(acc, disconnectCallback);// 將異步上下文與 libevent 事件循環綁定if (redisClusterLibeventAttach(acc, base) != 0) {std::cerr << "Failed to attach to libevent!" << std::endl;redisClusterAsyncFree(acc);event_base_free(base);return -1;}// 異步發送 SET 命令redisClusterAsyncCommand(acc, commandCallback, NULL, "SET %s %s", "foo", "bar");// 異步發送 GET 命令redisClusterAsyncCommand(acc, commandCallback, NULL, "GET %s", "foo");// 啟動事件循環event_base_dispatch(base);// 釋放資源redisClusterAsyncFree(acc);event_base_free(base);return 0;
}

?


?

<libevent.h>

<hiredis-vip/adapters/libevent.h>是 hiredis-vip 提供的 Libevent 適配器模塊,用于將異步 Redis/Redis Cluster 客戶端集成進基于 libevent 的事件驅動程序中,實現非阻塞式通信。

  • hiredis-vip 支持 異步模式:你發命令出去,不會等 Redis 響應,你繼續干別的事。響應來了,它會回調你,告訴你結果。

  • 但是這時候需要一個人幫你“看著 socket”,當有數據能讀、能寫了時,提醒你去處理一下 , 這個人就是 libevent

  • 所以你要把 hiredis-vip 的 Redis 客戶端和 libevent 建立聯系:你告訴 libevent:你幫我盯著 hiredis 的 socket,有事了通知我。

  • hiredis-vip/adapters/libevent.h 就是負責搭橋的,讓這兩者能配合起來完成這一切。

在高性能網絡服務中,比如使用 libevent 寫的 HTTP 服務或消息系統,你不想因為一個 Redis 命令就阻塞整個線程,你希望:

  • 我發一個 SET 命令 → Redis 那邊處理它 → 回來后你再告訴我結果(回調函數)

  • 我整個服務的主線程仍然在跑,不停響應其他請求

  • 這種模式就必須用 非阻塞 I/O + 事件驅動 + 回調機制

這正是 libevent + hiredis-vip async 的組合實現的。

  • hiredis 提供了 redisAsyncContext:可以用它異步發送命令 + 設置回調處理響應。

  • 但它自己不處理 socket 的可讀/可寫通知,你要告訴一個 event loop 去“監聽 socket fd”

  • libevent 是個 event loop 框架,它可以 event_add() 來監聽 socket 的各種事件

  • 所以 redisLibeventAttach() 就是把兩者連接起來,把 redisAsyncContext 的 socket 交給 libevent 管

  • 以后 Redis 響應來了,libevent 會幫你觸發你之前設置的回調函數


API

redisLibeventAttach

將 Redis 上下文(無論是同步的 redisContext 還是異步的 redisAsyncContext)與 libevent 事件循環綁定,使得 Redis 能夠使用 libevent 進行非阻塞的 I/O 操作。

int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base);
  • 參數

    • c:指向 異步Redis 上下文的指針=。

    • baselibevent 事件循環的基礎對象,通常是通過 event_base_new() 創建。

  • 返回值

    • 成功時返回 0

    • 失敗時返回 -1

示例:

#include <iostream>
#include <hiredis-vip/hiredis.h>
#include <hiredis-vip/adapters/libevent.h>
#include <event.h>// 回調函數:處理 Redis 響應
void reply_callback(redisAsyncContext *c, void *r, void *privdata) {redisReply *reply = (redisReply *)r;if (reply == nullptr) {std::cerr << "Error: " << c->errstr << std::endl;return;}std::cout << "Redis reply: " << reply->str << std::endl;
}int main() {// 1. 創建 libevent 事件基礎對象struct event_base *base = event_base_new();if (!base) {std::cerr << "Error creating event base." << std::endl;return -1;}// 2. 創建異步 Redis 上下文并連接 Redis 服務器redisAsyncContext *ac = redisAsyncConnect("127.0.0.1", 6379);if (ac == nullptr || ac->err) {std::cerr << "Connection error: " << (ac ? ac->errstr : "Unknown error") << std::endl;return -1;}// 3. 將異步 Redis 上下文綁定到 libevent 事件循環if (redisLibeventAttach(ac, base) != 0) {std::cerr << "Error attaching Redis context to libevent." << std::endl;return -1;}// 4. 發送一個 Redis 命令并設置回調函數redisAsyncCommand(ac, reply_callback, nullptr, "SET %s %s", "key", "value");// 5. 啟動事件循環,開始處理異步事件event_base_dispatch(base);// 6. 清理redisAsyncFree(ac);event_base_free(base);return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79871.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79871.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79871.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

go 通過匯編學習atomic原子操作原理

文章目錄 概要一、原理1.1、案例1.2、關鍵匯編 二、LOCK匯編指令2.1、 LOCK2.2、 原理2.2.1、 緩存行2.2.2、 緩存一致性之MESI協議2.2.3、lock原理 三、x86緩存發展四、x86 DMA發展參考 概要 在并發操作下&#xff0c;對一個簡單的aa2的操作都會出錯&#xff0c;這是因為這樣…

mapreduce打包運行

maven打包 MapReduce是一個分布式運算程序的編程框架&#xff0c;是用戶開發“基于Hadoop的數據分析應用”的核心框架。 MapReduce核心功能是將用戶編寫的業務邏輯代碼和自帶默認組件整合成一個完整的分布式運算程序&#xff08;例如&#xff1a;jar包&#xff09;&#xff0…

小白成長之路-LInux系統文件與目錄管理(二)

提示&#xff1a;第二部分對第一部分收尾 文章目錄 常見的命令如下一、文件查看命令1. more命令2.less命令3.head命令4.tail命令5.nl命令&#xff08;了解&#xff09;6.創建目錄命令7.創建文件命令>: 覆蓋重定向>>: 追加重定向 8.touch命令9.echo命令10.文件或目錄復…

JVM之虛擬機運行

虛擬機運行快速復習 try-catch&#xff1a;catch-異常表棧展開&#xff0c;finally-代碼復制異常表兜底 類的生命周期&#xff1a;加載&#xff0c;連接&#xff08;驗證&#xff0c;準備&#xff0c;解析&#xff09;&#xff0c;初始化&#xff0c;使用&#xff0c;卸載 類…

AI數字人實現原理

隨著人工智能與數字技術的快速發展&#xff0c;AI數字人&#xff08;Digital Human&#xff09;作為新一代人機交互媒介&#xff0c;正在多個行業中快速落地。無論是在虛擬主播、在線客服、教育培訓&#xff0c;還是在數字代言、元宇宙中&#xff0c;AI數字人都扮演著越來越重要…

Android開發-數據庫SQLite

在Android應用開發中&#xff0c;當需要存儲結構化數據時&#xff0c;SQLite是一個非常強大的工具。SQLite是一款輕量級的關系型數據庫管理系統&#xff0c;它內嵌于Android系統中&#xff0c;支持SQL語法&#xff0c;并且不需要單獨的服務器進程或系統配置。本文將介紹如何在A…

android實現USB通訊

在 Android 上枚舉 USB 設備除了使用 UsbManager.getDeviceList() 方法外&#xff0c;還有以下幾種常見的方式&#xff1a; 1. 使用 USB 設備過濾器&#xff08;XML 配置&#xff09; 通過在 AndroidManifest.xml 中配置 USB 設備過濾器&#xff0c;可以讓系統自動檢測并通知…

FFmpeg視頻編碼的完整操作指南

步驟如下&#xff1a; 安裝和準備FFmpeg&#xff1a;確保包含所需編碼器&#xff08;如libx264&#xff09;。基本命令行編碼&#xff1a;使用ffmpeg命令進行轉碼&#xff0c;設置視頻編碼器、CRF、預設等。API編碼流程&#xff08;針對開發者&#xff09;&#xff1a; a. 注冊…

鴻蒙 UIAbility組件與UI的數據同步和窗口關閉

使用 EventHub 進行數據通信 Stage模型概念圖 根據 Stage 模型概念圖 UIAbility 先于 ArkUI Page 創建 所以&#xff0c;事件要先 .on 訂閱 再 emit 發布 假如現在有頁面 Page1 和他的 UIAbility // src/main/ets/page1ability/Page1Ability.ets onCreate(want: Want, laun…

全棧工程師實戰手冊:LuatOS日志系統開發指南!

本文聚焦LuatOS-log庫的實戰應用場景&#xff0c;通過完整案例演示日志模塊集成、格式定制及遠程同步方案&#xff0c;幫助全棧開發者構建靈活可靠的日志管理框架。下面&#xff0c;我們一起來認識LuatOS的log庫&#xff01; 一、 log.info() log info()主要打印一些正常的…

STM32-USART串口通信(9)

一、通信接口介紹 通信的目的&#xff1a;將一個設備的數據傳送到另一個設備&#xff0c;擴展硬件系統。 當STM32想要實現一些功能&#xff0c;但是需要外掛一些其他模塊才能實現&#xff0c;這就需要在兩個設備之間連接上一根或多跟通信線&#xff0c;通過通信線路發送或者接…

【MoveIt 2】使用 MoveIt 任務構造器(MoveIt Task Constructor)進行拾取和放置

本教程將引導您創建一個使用 MoveIt 任務構造器規劃抓取和放置操作的包。MoveIt 任務構造器&#xff08;https://github.com/moveit/moveit_task_constructor/tree/ros2/&#xff09;提供了一種為包含多個不同子任務&#xff08;稱為階段&#xff09;的任務進行規劃的方法。如果…

破解商業綜合體清潔管理困局:商業空間AI智能保潔管理系統全場景解決方案

方案整體概述 隨著商業綜合體日益向智能化、精細化管理轉型&#xff0c;傳統保潔工作面臨人員監管難、清潔效果評估難、應急響應滯后等諸多挑戰。為解決這些痛點&#xff0c;本系統依托計算機視覺、行為識別、圖像分割與深度學習等AI技術&#xff0c;構建一套集人員管理、工作…

spring響應式編程系列:異步消費數據

目錄 示例 大致流程 parallel cache PARALLEL_SUPPLIER newParallel init publishOn new MonoSubscribeOnValue ???????subscribe ???????new LambdaMonoSubscriber ???????MonoSubscribeOnValue.subscribe ???????onSubscribe ??…

視頻編解碼學習十二之Android疑點

一、android.view.SurfaceControl.setDisplaySurface的作用 android.view.SurfaceControl.setDisplaySurface 是 Android 系統中一個 native 層級別的 API&#xff0c;主要用于 設置某個物理顯示屏&#xff08;Display&#xff09;的輸出 Surface&#xff0c;屬于 SurfaceFlin…

家用或辦公 Windows 電腦玩人工智能開源項目配備核顯的必要性(含 NPU 及顯卡類型補充)

一、GPU 與顯卡的概念澄清 首先需要明確一個容易誤解的概念&#xff1a;GPU 不等同于顯卡。 顯卡和GPU是兩個不同的概念。 【概念區分】 在討論圖形計算領域時&#xff0c;需首先澄清一個常見誤區&#xff1a;GPU&#xff08;圖形處理單元&#xff09;與顯卡&#xff08;視…

Python----神經網絡(《Deep Residual Learning for Image Recognition》論文和ResNet網絡結構)

一、論文 1.1、論文基本信息 標題&#xff1a;Deep Residual Learning for Image Recognition 作者&#xff1a;Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 單位&#xff1a;Microsoft Research 會議&#xff1a;CVPR 2016 主要貢獻&#xff1a;提出了一種深度殘…

Qt/C++開發監控GB28181系統/錄像文件查詢/錄像回放/倍速播放/錄像文件下載

一、前言 搞定了實時預覽后&#xff0c;另一個功能就是錄像回放&#xff0c;錄像回放和視頻點播功能完全一致&#xff0c;唯一的區別就是發送點播的sdp信息中攜帶了開始時間和結束時間&#xff0c;因為是錄像文件&#xff0c;所以有這個時間&#xff0c;而實時視頻預覽這個對應…

在Spark搭建YARN

&#xff08;一&#xff09;什么是SparkONYarn模式 Spark on YARN&#xff08;Yet Another Resource Negotiator&#xff09;是 Spark 框架在 Hadoop 集群中運行的一種部署模式&#xff0c;它借助 Hadoop YARN 來管理資源和調度任務。 架構組成 ResourceManager&#xff1a;作…

SpringAI

機器學習&#xff1a; 定義&#xff1a;人工智能的子領域&#xff0c;通過數據驅動的方法讓計算機學習規律&#xff0c;進行預測或決策。 核心方法&#xff1a; 監督學習&#xff08;如線性回歸、SVM&#xff09;。 無監督學習&#xff08;如聚類、降維&#xff09;。 強化學…