一、引子:语言到底是怎么"连上" Redis 的
1.1 从 HTTP 博客得到的启发:协议先行
在 HTTP 那篇博客里我们分析过应用层协议,也自己实现了 Web 开发。当时得出的结论是:想要建立连接,最重要的是先把协议设计好。
所谓协议,就是通信双方事先约定好每一个字段的具体含义,并且实现对应的序列化(发送端编码)和反序列化(接收端解码)。只要双方遵守同一份协议,任何语言、任何库都能互相通信——这就是 Redis 能被 C++/Java/Python 等几十种语言连接的根本原因。
1.2 客户端库的本质三要素
一个 Redis 客户端库,本质上只做三件事:
| 网络连接 | 建立 TCP 连接、发送/接收字节流 | socket 层 |
| 协议编码 | 把命令序列化成 RESP 字节流 | 序列化 |
| 协议解码 | 把服务器返回的字节流解析成结构 | 反序列化 |
Redis 定义了协议,各语言社区基于协议实现了各自的客户端库。MySQL 同理(MySQL 协议 + Connector/C++ 等)。
二、RESP 协议详解
2.1 传输层协议
- Redis 官方实现中,RESP 协议承载在 TCP(默认 6379 端口)或 Unix Domain Socket 上;
- 官方不支持 UDP 传输;
- 原因:数据库场景要求数据精确、不丢失、有序到达,TCP 的可靠字节流正好满足;UDP 不保证可靠性和顺序,只适合音视频、游戏帧这类"丢了就丢了"的场景。
2.2 RESP 的五种基本数据类型
RESP(REdis Serialization Protocol)是 Redis 自己设计的文本协议,一共 5 种类型:
| 简单字符串 | + | +OK\\r\\n | 状态回复 |
| 错误 | – | -ERR unknown command\\r\\n | 错误信息 |
| 整数 | : | :1000\\r\\n | 整数回复(如 INCR) |
| 批量字符串 | $ | $6\\r\\nfoobar\\r\\n | 二进制安全的字符串,$ 后是字节数 |
| 数组 | * | *2\\r\\n… | 多条消息的集合 |
2.3 一个命令的完整序列化实例
客户端发送 SET name zhangsan,实际在 TCP 上传输的字节流是:
*3\\r\\n$3\\r\\nSET\\r\\n$4\\r\\nname\\r\\n$8\\r\\nzhangsan\\r\\n
逐段拆解:
| *3 | 数组,共 3 个元素(命令名 + 两个参数) |
| $3\\r\\nSET | 批量字符串,长度 3,内容是 SET |
| $4\\r\\nname | 批量字符串,长度 4,内容是 name |
| $8\\r\\nzhangsan | 批量字符串,长度 8,内容是 zhangsan |
服务器返回 OK 时,回复就是 +OK\\r\\n。这就是序列化和反序列化的全部秘密——看到这里你应该明白,自己动手写一个迷你客户端是完全可行的。
三、C++ 客户端选型:hiredis 与 redis-plus-plus
3.1 hiredis:Redis 官方 C 客户端
- 由 Redis 官方组织维护(redis/hiredis);
- 提供同步 API(redisConnect + redisCommand + redisReply)和异步 API(redisAsyncContext + 事件循环);
- 是很多其他语言客户端的底层基石。
3.2 redis-plus-plus:基于 hiredis 的 C++ 封装
- 作者 sewenew,仓库 https://github.com/sewenew/redis-plus-plus;
- 底层依赖 hiredis,但面向 C++ 重新设计了接口:Redis、RedisCluster、RedisSentinel、连接池、管道、事务、发布订阅等;
- 符合现代 C++ 习惯(RAII、异常、可选值),这就是我们选它的原因。
3.3 选型对比
| 语言 | C | C++ |
| 维护方 | Redis 官方 | 社区(sewenew) |
| 接口风格 | C 函数 + 手动管理内存 | 类封装 + RAII |
| 连接池/集群 | 需自己写 | 内置 |
| 我们的选择 | 作为底层依赖 | ✅ 主用 |
四、库的获取与安装
4.1 安装 hiredis:apt 一行搞定(从镜像源下载)
sudo apt install libhiredis-dev
libhiredis-dev 是开发包,同时包含头文件(/usr/include/hiredis/hiredis.h)和库文件(/usr/lib/x86_64-linux-gnu/libhiredis.a 与 .so)。
4.2 拉取并编译 redis-plus-plus:
git clone https://github.com/sewenew/redis-plus-plus
cd redis-plus-plus
sudo apt install cmake # 安装 cmake 工具
mkdir build && cd build # build 目录:隔离生成文件,防止污染源码目录(不只是"好看")
cmake .. # ⚠️ 由 CMakeLists.txt 生成 Makefile(关键步骤)
make # 编译,产出静态库 libredis++.a
sudo make install # 安装到 /usr/local 下
说明:CMakeLists.txt 是构建脚本,cmake .. 负责把它翻译成 Makefile(也可以生成 Ninja 等),之后 make 编译是将对应.o文件包装成动静态库(这里只有静态库)、make install 把产物拷贝到系统路径。多数主流开源库都是这条流程。
4.3 apt 安装 vs 源码编译的区别
| 头文件位置 | /usr/include 等默认路径 | 手动 make install 到 /usr/local/include |
| 库文件位置 | /usr/lib/x86_64-linux-gnu/ | /usr/local/lib/ |
| 编译时 | 不需要手动写路径 | 头文件/库路径一般也要靠默认目录或手动指定 |
| 灵活性 | 只能用仓库里的版本 | 可自定义编译选项(如 C++ 标准) |
apt 安装是优选,git 安装之后 make 要消耗时间
4.4 验证安装产物位置
# 头文件(编译期需要,供 #include 使用)
find /usr -name "redis++.h"
# → /usr/local/include/sw/redis++/redis++.h
# 所以代码里写: #include <sw/redis++/redis++.h>
# 库文件(链接期需要)
find /usr -name "libredis++*"
# → /usr/local/lib/libredis++.a
为什么在/usr路径下find?因为大部分都是默认安装到这里的
五、编译与链接细节
5.1 静态库链接
redis-plus-plus 默认构建的是静态库。
5.2 三种正确的链接写法
⚠️ -l 选项后面只能跟库名(去掉 lib 前缀和 .a/.so 后缀),不能跟完整路径。
写法一:直接给完整路径(把 .a 文件当普通输入文件)
g++ -std=c++17 main.cpp /usr/local/lib/libredis++.a \\
/usr/lib/x86_64-linux-gnu/libhiredis.a -lpthread -o app
写法二:-L 指定搜索目录 + -l 指定库名(推荐,最常用)
g++ -std=c++17 main.cpp -L/usr/local/lib -lredis++ \\
-L/usr/lib/x86_64-linux-gnu -lhiredis -lpthread -o app
写法三:默认路径直接用 -l(apt 装好的 hiredis 已在默认路径,-L 可省)
g++ -std=c++17 main.cpp -lredis++ -lhiredis -lpthread -o app
要点:-lredis++ 实际会被解析成"去 -L 目录里找 libredis++.a(或 .so)"
5.4 链接顺序与常见坑
六、如何登录GitHub及后续源码查询
6.1 访问GitHub
6.2 后续学习
关于 redis 的各种数据结构具体的 API 使用及细节,可以参考我的源码,里面注释自认为还是比较详细的 bksczm/redis_test: Repository for Redis testing exercises
感谢支持




