一、引子:语言到底是怎么"连上" 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 选型对比
| 维度 | hiredis | redis-plus-plus |
|---|---|---|
| 语言 | 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 源码编译的区别
| 维度 | apt 安装 | git 源码编译 |
|---|---|---|
| 头文件位置 | /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 链接顺序与常见坑
- 顺序 :静态库之间有依赖时,被依赖的放后面 ------
libredis++.a依赖 hiredis,所以-lredis++必须写在-lhiredis前面; - C++ 标准 :redis-plus-plus 用到了较新的 C++ 特性,编译时加
-std=c++17(至少-std=c++11); - hiredis 找不到 :如果 hiredis 不是 apt 装的(自己编译的),cmake 阶段用
-DHIREDIS_ROOT=路径指定; - pthread :新版本 glibc 已把 pthread 并入 libc,但显式
-lpthread兼容性最好,加上无妨。
六、如何登录GitHub及后续源码查询
6.1 访问GitHub
- magic (违法),不宣传,不支持
- 使用加速器,我们这里使用stream的加速器,watt toolkit (免费),对GitHub加速之后就可以使用通过代理服务器的方式进行访问
6.2 后续学习
关于 redis 的各种数据结构具体的 API 使用及细节,可以参考我的源码,里面注释自认为还是比较详细的 bksczm/redis_test: Repository for Redis testing exercises
感谢支持