hiredis 是 redis 官方推荐的 c 客户端库,c++ 项目应直接使用而非自行封装 socket;需检查 redisconnect 返回值、用 redisconnectwithtimeout 设置超时、及时 auth/select、避免多线程共享 context、正确处理 redisreply 的空值与类型、用 freereplyobject 释放内存、二进制数据须用 %b 和 reply->len、不依赖自动重连、建议使用连接池。

用 hiredis 连 Redis,别直接 new socket
Redis 官方不提供 C++ 原生客户端,hiredis 是最稳的 C 库,C++ 项目里直接用它就行,别自己封装 TCP 连接——容易漏掉连接复用、超时重试、协议解析这些坑。
常见错误现象:redisConnect 返回 NULL 却没检查 c->err;连上后发命令返回 NULL,其实是认证失败或命令格式错,不是网络断了。
- 必须用
redisConnectWithTimeout替代redisConnect,硬编码超时(比如 2 秒),否则 DNS 卡住会阻塞整个线程 - 连接成功后立刻发
AUTH(如果有密码)或SELECT(如果指定了 db),别等到第一次业务命令才处理 - 不要在多线程里共用一个
redisContext*,hiredis不是线程安全的;每个线程要么独占 context,要么用连接池
redisCommand 返回值怎么判断对错
返回 NULL 不等于“命令执行失败”,它只表示通信层出问题(连接断、协议错、内存不足);真正的业务错误(比如 KEY_NOT_EXIST)会以 redisReply* 形式返回,type 字段是 REDIS_REPLY_ERROR。
使用场景:读写 SET/GET、执行 INCR、批量 PIPELINE 前的单条诊断命令。
- 每次调用
redisCommand后,先判空:if (!reply) { /* 看 c->errstr */ } - 再判类型:
if (reply->type == REDIS_REPLY_ERROR),然后读reply->str拿具体错误信息 -
redisReply必须用freeReplyObject释放,不释放会内存泄漏——尤其在循环里反复调用时
字符串和二进制数据混用时的编码陷阱
hiredis 默认把所有 reply 当作 UTF-8 字符串处理,但 Redis 本身存的是 raw bytes。如果你存的是图片、protobuf 或加密后的二进制,用 reply->str 直接取内容会截断(遇到
hiredis 默认把所有 reply 当作 UTF-8 字符串处理,但 Redis 本身存的是 raw bytes。如果你存的是图片、protobuf 或加密后的二进制,用 reply->str 直接取内容会截断(遇到 \0 就停),且长度不准。
参数差异:redisReply 的 str 字段只保证以 \0 结尾,但真实数据可能含 \0;len 字段才是实际字节数。
- 存二进制前,确保用
redisCommand(c, "SET %b %b", key, key_len, val, val_len),别用%s - 取二进制时,别用
std::string(reply->str),改用std::string(reply->str, reply->len) - 如果 key 本身含非 ASCII 字符(比如中文路径),也得用
%b,否则 redis 可能按字节截断或乱码
连接断开后自动重连不可信
hiredis 不做自动重连,redisGetReply 或 redisCommand 遇到断连只会返回 NULL,不会尝试重建连接。靠外部轮询 context->err 并手动 redisReconnect 很容易漏状态或重复初始化。
性能影响:频繁重连比维持长连接慢 10 倍以上,尤其在云环境(DNS 解析 + TLS 握手开销大)。
- 别在每次操作前检查
context->err,而是在首次失败后标记 context 为 invalid,下次操作前统一重建 - 用
redisSetTimeout设置 socket 超时,避免redisCommand卡死;配合select()或epoll做异步等待更稳妥 - 生产环境建议套一层轻量连接池(比如固定 4–8 个 context),比单连接 + 重连更可控
最麻烦的其实是 pipeline 中某条命令失败后,后续 reply 的偏移全乱了——这时候不能只看最后一条 reply,得用 redisGetReply 逐个收,否则容易把错误响应当成下一条的正常结果。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











