10分钟就理解Redis序列化协议,你也能编写redis客户端( 三 )


第一个字节 前缀长度 CRLF 字符串内容 CRLF 定长字符串 $ 6 rn foobar rn ===> $6rnfoobarrn 表示空字符串(Empty String,对应Java中的"") 的时候,使用定长字符串编码如下:
第一个字节 前缀长度 CRLF CRLF 定长字符串 $ 0 rn rn ===> $0rnrn 定长字符串也可以使用特殊的格式来表示Null值,指代值不存在 。在这种特殊格式中,前缀长度为-1,并且没有数据,因此使用定长字符串对Null值进行编码如下:
第一个字节 前缀长度 CRLF 定长字符串 $ -1 rn ===> $-1rn 当Redis服务端返回定长字符串编码的Null值的时候,客户端不应该返回空字符串,而应该返回对应编程语言中的Null对象 。例如Ruby中对应nil,C语言中对应NULL,Java中对应null,以此类推 。
RESP数组-Array
Redis客户端使用RESP数组发送命令到Redis服务端 。与此相似,某些Redis命令执行完毕后服务端需要使用RESP数组类型将元素集合返回给客户端,如返回一个元素列表的LRANGE命令 。RESP数组和我们认知中的数组并不完全一致,它的编码格式如下:

  • (1)第一个字节为* 。
  • (2)紧接着的是组成RESP数组的元素个数(十进制数,但是最终需要转换为字节序列,如10需要转换为1和0两个相邻的字节),元素个数分块以CRLF终止 。
  • (3)RESP数组的每个元素内容,每个元素可以是任意的RESP数据类型 。
一个空的RESP数组的编码如下:
*0rn复制代码一个包含2个定长字符串元素内容分别为foo和bar的RESP数组的编码如下:
*2rn$3rnfoorn$3rnbarrn复制代码通用格式就是:*<count>CRLF作为RESP数组的前缀部分,而组成RESP数组的其他数据类型的元素只是一个接一个地串联在一起 。例如一个包含3个整数类型元素的RESP数组的编码如下:
*3rn:1rn:2rn:3rn复制代码RESP数组的元素不一定是同一种数据类型,可以包含混合类型的元素 。例如下面是一个包含4个整数类型元素和1个定长字符串类型元素(一共有5个元素)的RESP数组的编码(为了看得更清楚,分多行进行编码,实际上不能这样做):
# 元素个数*5rn# 第1个整型类型的元素:1rn# 第2个整型类型的元素:2rn# 第3个整型类型的元素:3rn# 第4个整型类型的元素:4rn# 定长字符串类型的元素$6rnfoobarrn复制代码Redis服务端响应报的首行*5rn定义了后面会紧跟着5个回复数据,然后每个回复数据分别作元素项,构成了用于传输的多元素定长回复(Multi Bulk Reply,感觉比较难翻译,这里的大概意思就是每个回复行都是整个回复报中的一个项) 。
这里可以类比为Java中的ArrayList(泛型擦除),有点类似于下面的伪代码:
List encode = new ArrayList();// 添加元素个数encode.add(elementCount);encode.add(CRLF);// 添加第1个整型类型的元素 - 1encode.add(':');encode.add(1);encode.add(CRLF);// 添加第2个整型类型的元素 - 2encode.add(':');encode.add(2);encode.add(CRLF);// 添加第3个整型类型的元素 - 3encode.add(':');encode.add(3);encode.add(CRLF);// 添加第4个整型类型的元素 - 4encode.add(':');encode.add(4);encode.add(CRLF);// 添加定长字符串类型的元素encode.add('$');// 前缀长度encode.add(6);// 字符串内容encode.add("foobar");encode.add(CRLF);复制代码RESP数组中也存在Null值的概念,下面称为RESP Null Array 。处于历史原因,RESP数组中采用了另一种特殊的编码格式定义Null值,区别于定长字符串中的Null值字符串 。例如,BLPOP命令执行超时的时候,就会返回一个RESP Null Array类型的响应 。RESP Null Array的编码如下:
*-1rn复制代码当Redis服务端的回复是RESP Null Array类型的时候,客户端应该返回一个Null对象,而不是一个空数组或者空列表 。这一点比较重要,它是区分回复是空数组(也就是命令正确执行完毕,返回结果正常)或者其他原因(如BLPOP命令的超时等)的关键 。
RESP数组的元素也可以是RESP数组,下面是一个包含2个RESP数组类型的元素的RESP数组,编码如下(为了看得更清楚,分多行进行编码,实际上不能这样做):
# 元素个数*2rn# 第1个RESP数组元素*3rn:1rn:2rn:3rn# 第2个RESP数组元素*2rn+Foorn-Barrn复制代码上面的RESP数组的包含2个RESP数组类型的元素,第1个RESP数组元素包含3个整型类型的元素,而第2个RESP数组元素包含1个简单字符串类型的元素和1个错误消息类型的元素 。
RESP数组中的Null元素
RESP数组中的单个元素也有Null值的概念,下面称为Null元素 。Redis服务端回复如果是RESP数组类型,并且RESP数组中存在Null元素,那么意味着元素丢失,绝对不能用空字符串替代 。缺少指定键的前提下,当与GET模式选项一起使用时,SORT命令可能会发生这种情况 。


推荐阅读