# 简介
几乎所有的主流编程语言都有Redis的客户端(http://redis.io/clients),不考虑Redis非常流行的原因,如果站在技术的角度看原因还有两个:
客户端与服务端之间的通信协议是在 TCP 协议之上构建的。
客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 。
客户端和服务器发送的命令或数据一律以
\r\n
(CRLF)结尾。Redis制定了 RESP(REdis Serialization Protocol,Redis序列化协议)实现客户端与服务端的正常交互,这种协议简单高效,既能够被机器解析,又容易被人类识别。
发送命令
RESP 在 Redis 1.2 版本中引入, 并最终在 Redis 2.0 版本成为 Redis 服务器通信的标准方式。
在这个协议中, 所有发送至 Redis 服务器的参数都是二进制安全(binary safe)的。
RESP 的规定一条命令的格式如下:
*<参数数量> CR LF $<参数 1 的字节数量> CR LF <参数 1 的数据> CR LF ... $<参数 N 的字节数量> CR LF <参数 N 的数据> CR LF
命令本身也作为协议的其中一个参数来发送。
例如我们经常执行的 SET 命令,在命令行中我们输入如下:
SET key value
使用 RESP 协议规定的格式:
*3 $3 SET $3 # 这里 key 一共三个字节 key $5 # 这里 value 一共五个字节 value
这个命令的实际协议值如下:
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"
回复
Redis 命令会返回多种不同类型的回复。
通过检查服务器发回数据的第一个字节, 可以确定这个回复是什么类型:
- 状态回复(status reply)的第一个字节是
"+"
- 错误回复(error reply)的第一个字节是
"-"
- 整数回复(integer reply)的第一个字节是
":"
- 批量回复(bulk reply)的第一个字节是
"$"
- 多条批量回复(multi bulk reply)的第一个字节是
"*"
我们知道redis-cli只能看到最终的执行结果,那是因为redis-cli本身就按照RESP进行结果解析的,所以看不到中间结果,redis-cli.c 源码对命令结果的解析结构如下:
static sds cliFormatReplyTTY(redisReply *r, char *prefix) { sds out = sdsempty(); switch (r->type) { // 处理错误回复 case REDIS_REPLY_ERROR: out = sdscatprintf(out,"(error) %s\n", r->str); break; // 处理状态回复 case REDIS_REPLY_STATUS: out = sdscat(out,r->str); out = sdscat(out,"\n"); break; // 处理整数回复 case REDIS_REPLY_INTEGER: out = sdscatprintf(out,"(integer) %lld\n",r->integer); break; // 处理字符串回复 case REDIS_REPLY_STRING: /* If you are producing output for the standard output we want * a more interesting output with quoted characters and so forth */ out = sdscatrepr(out,r->str,r->len); out = sdscat(out,"\n"); break; // 处理 nil case REDIS_REPLY_NIL: out = sdscat(out,"(nil)\n"); break; // 处理多回复 case REDIS_REPLY_ARRAY: if (r->elements == 0) { out = sdscat(out,"(empty list or set)\n"); } else { unsigned int i, idxlen = 0; char _prefixlen[16]; char _prefixfmt[16]; sds _prefix; sds tmp;
- 状态回复(status reply)的第一个字节是