C++ 本身不内置 Redis 客户端,必须依赖第三方库;hiredis 是最轻量、最常用、官方推荐的 C/C++ 客户端,但仅支持同步阻塞模式,无异步和连接池功能。

直接说结论:C++ 本身不内置 Redis 客户端,必须依赖第三方库;hiredis 是最轻量、最常用、也是官方推荐的 C/C++ 客户端,但它是同步阻塞的,不支持异步或连接池——这点很多人用了一两个月才发现卡在高并发场景。
为什么选 hiredis 而不是 redis-plus-plus 或 cpp_redis
hiredis 是 Redis 官方维护的底层 C 库,稳定、无依赖、编译快;redis-plus-plus 功能强(支持异步、连接池、STL 容器自动序列化),但依赖 hiredis + openssl + g++17+,线上部署容易因 OpenSSL 版本不一致崩溃;cpp_redis 已停止维护。如果你只需要简单 SET/GET,hiredis 足够且更可控。
常见错误现象:undefined reference to `redisConnect' —— 多半是链接时没加 -lhiredis,或者头文件路径没配对(#include 对应的是安装后的 include 路径,不是源码目录)。
- Ubuntu/Debian 下装:
sudo apt install libhiredis-dev(含头文件和静态/动态库) -
macOS 用 Homebrew:
brew install hiredis - 手动编译:从 GitHub clone 后
make && sudo make install,注意默认不安装头文件到/usr/local/include,可能需要sudo cp hiredis.h async.h read.h sds.h /usr/local/include/hiredis/
redisContext* 连接对象必须检查 c->err,不能只看指针是否为空
redisConnect 返回 NULL 确实代表失败,但更常见的是返回非空指针、而 c->err == 1(即出错但结构体已分配)。比如密码错误、Redis 拒绝连接、DNS 解析失败,都会进这个“假成功”分支。
立即学习“C++免费学习笔记(深入)”;
正确写法:
redisContext *c = redisConnect("127.0.0.1", 6379);
if (c == NULL || c->err) {
if (c) {
fprintf(stderr, "Connection error: %s\n", c->errstr);
redisFree(c);
}
return -1;
}
漏掉 c->err 判断,后续调用 redisCommand 可能 segfault 或返回 NULL 却不报错,调试极其困难。
redisCommand 返回值类型多变,redisReply* 的 type 字段决定怎么取值
redisCommand 总是返回 redisReply*,但它的 type 成员可能是 REDIS_REPLY_STRING、REDIS_REPLY_INTEGER、REDIS_REPLY_ARRAY 等——不查 type 就直接访问 reply->str,遇到 INCR 返回整数时会 crash。
典型安全读取模式:
redisReply *reply = (redisReply*)redisCommand(c, "GET %s", "mykey");
if (!reply) {
fprintf(stderr, "Redis command failed\n");
redisFree(c);
return -1;
}
if (reply->type == REDIS_REPLY_STRING) {
printf("Value: %s\n", reply->str);
} else if (reply->type == REDIS_REPLY_NIL) {
printf("Key not exists\n");
} else if (reply->type == REDIS_REPLY_INTEGER) {
printf("Count: %lld\n", reply->integer);
} else {
printf("Unexpected reply type: %d\n", reply->type);
}
freeReplyObject(reply); // 必须调用,否则内存泄漏
-
SET、DEL等命令返回REDIS_REPLY_STATUS,可用reply->str判断是否为"OK" -
LRANGE返回REDIS_REPLY_ARRAY,需遍历reply->element[i] - 所有
redisReply*必须用freeReplyObject释放,不能用free()或delete
没有连接池、没有自动重连,得自己兜底
hiredis 不管理连接生命周期。网络闪断、Redis 重启后,旧 redisContext* 会处于不可用状态,但 c->err == 0,redisCommand 可能返回 NULL 或阻塞超时。生产环境必须实现重连逻辑,且不能每次操作都新建连接(开销大)。
最小可行方案:
- 封装一个连接句柄结构体,含
redisContext*和最后成功时间 - 每次操作前检查
c->err或用redisPing探活(注意redisPing也返回redisReply*,要判type) - 失败时
redisFree(c)+redisConnect重建,最多重试 2–3 次 - 避免全局单例
redisContext*,多线程必须每个线程独占连接(hiredis非线程安全)
真正麻烦的不是连不上,而是连上了却发不出命令——比如 Redis 设置了 maxclients 上限,或客户端未及时 freeReplyObject 导致连接被服务端踢出,这种问题在线上压测时才暴露,日志里只看到大量 Connection refused,实际是连接被复用污染了。









