译文
Redis协议详细说明 (Redis Protocol specification)
Redis客户端使用RESP(Redis的序列化协议)协议与Redis的服务器端进行通信. 虽然该协议是专门为Redis设计的,但该协议也可以用于其他 客户端-服务器 (Client-Server)软件项目。
RESP是对以下几件事情的折中实现:
- 实现简单
- 快速解析
- 人类可读
RESP可以序列化不同的数据类型,如整数(integers),字符串(strings),数组(arrays). 它还使用了一个特殊的类型来表示错误(errors). 请求以字符串数组的形式来表示要执行命令的参数从客户端发送到Redis服务器. Redis使用命令特有(command-specific)数据类型作为回复.
RESP协议是二进制安全的(binary-safe),并且不需要处理从一个进程传输到另一个进程的块数据的大小,因为它使用前缀长度(prefixed-length)的方式来传输块数据的.
注意: 该文章所说的协议仅用于 客户端 - 服务器(Client-Server)的通信. Redis集群使用不同的二进制协议来交换节点之间的消息.
binary-safe:
维基百科上对 “二进制安全” 的解释:
Binary-safe is a computer programming term mainly used in connection with string manipulating functions.
A binary-safe function is essentially one that treats its input as a
raw stream of data without any specific format. It should thus work with
all 256 possible values that a character can take (assuming 8-bit characters).
翻译为:
二进制安全是一种主要用于字符串操作函数相关的计算机编程术语。二进制安全函数,本质上是将原始的数据流输入作为无任何特殊格式对待的。其在操作上应包含一个字符所能有的256种可能的值(假设为8 bit)。
简单理解就是,输入什么,其在运行过程中就是什么,不会将某字符挪作他用.
举栗: 输入"abc\0abc", 输出也应该是"abc\0abc". 但是在c中的strlen函数就不是binary safe的,因为它依赖于特殊的字符’\0’来判断字符串是否结束,所以对于字符串str = "1234\0123"来说, strlen(str)=4, 而二进制安全情况下应为8.
网络层 (Networking layer)
客户端通过创建到端口6379的TCP连接,连接到Redis的服务器。
尽管,RESP协议是非TCP专用的技术,但在Redis的环境中,该协议仅用于TCP连接(或类似于Unix套接字的面向流的连接)。
请求-响应模型 (Request-Response model)
Redis接收不同参数组成的命令.一旦命令被接收,将被处理然后发送给客户端回答.
这是最简单的模型,然而有2个例外:
- Redis支持管道操作(稍后会在本文档中介绍).因此支持客户可能的一次发送多个命令,等待稍后回复.
- 当Redis客户端订阅 Pub/Sub 模式的channel时,协议会改变语义变成push协议,也就是说,客户端不再需要发送命令,因为服务器一旦收到消息就会自动向客户端发送该新消息(对于订阅了通道的客户端).
除了上述两个例外,Redis协议就是个简单的 请求-响应 协议。
RESP协议描述 (RESP protocol description
RESP协议在Redis 1.2版本中引入,但它在Redis 2.0版本中与Redis服务器沟通的标准方式.这协议您应该在Redis客户端中实现的.
RESP实际上是支持以下数据类型的序列化协议: 简单字符串(Simple Strings
),错误(Errors
),整数(Integers
),块字符串(Bulk Strings
)和数组(Arrays
).
- 客户端将命令作为批量字符串的RESP数组发送到Redis服务器.
- 服务器(Server)根据命令执行的)实现返回一个具体的RESP类型作为回复.
RESP中的一些数据类型依赖首字节:
- 对于
Simple Strings
,首字节回复为"+" - 对于
Errors
,首字节回复为"-" - 对于
Integers
, 首字节回复为":" - 对于
Bulk Strings
, 首字节回复为"$" - 对于
Arrays
,首字节回复为"*"
此外,稍后会讲RESP协议能够使用指定的 Bulk Strings 或 Array 的特殊变量来表示空值.
在RESP协议中,协议的不同部分始终以“\r\n”(CRLF1)结尾.
RESP Simple Strings
简单字符串按以下方式编码: 以’+’(加号字符)开始,后跟一个不能包含CR或LF字符(不允许新行)的字符串,以CRLF(即“\r\n”)结尾。
简单字符串用于以最小开销传输非二进制安全的字符串.例如,许多Redis命令在成功时回复“OK”, 作为一个RESP Simple String
以下5个字节进行编码:
"+OK\r\n"
为了发送二进制安全的字符串,需要使用RESP Bulk Strings
.
当Redis以简Simple Strings
回复时,客户端库应该返回给调用者一个首字符’+'后直到字符串结尾组成的字符串,不包括最终的CRLF字节.(如上面例子的"OK"部分)
RESP Errors
RESP协议有特定数据类型表示错误. 实际上, 错误与RESP Simple Strings
完全相同,但第一个字符是减号’ - '而不是加号. Simple Strings
和 Errors
在RESP中之间的真正区别在于Errors
被客户端视为异常, 而组成错误类型的字符串本身就是错误信息.
基本格式为:
"-Error message\r\n"
Errors
回复仅在发生错误时发送,例如,如果您尝试针对错误的数据类型执行操作,或者命令不存在等. 当收到错误应答时,客户端就应该抛出一个异常.
以下是错误回复的示例:
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value
"-“之后的第一个单词,直到第一个空格或换行符,表示返回的错误种类. 这只是Redis使用的一种习惯,并不是RESP Error
格式的一部分.
例如,ERR
是通用错误,而WRONGTYPE
是一个更具体的错误,意味着客户端试图针对错误的数据类型执行操作. 这(指”-"之后的第一个单词)被称为错误前缀,并且是一种允许客户端不依赖给定的确切消息而了解服务器返回的错误类型的方式,该消息可能随时间而改变.
客户端实现可能会针对不同的错误返回不同类型的异常, 或者可能会提供一种通用方法来通过直接将错误名称作为字符串提供给调用者来捕获错误.
然而, 这样的功能不应该被认为是至关重要的, 因为它作用很小, 而针对客户端有限的实现来说可能仅仅返回一个通用错误条件, 例如 false .
RESP Integers
这种以":“字节为前缀, 并且只以一个CRLF终止的字符串类型表示为整数. 例如”:0\r\n"或":1000\r\n"是整数回复.
许多Redis命令返回RESP Integers
, 如 INCR
, LLEN
和 LASTSAVE
.
返回的整数没有特殊含义,对与INCR
它只是一个增量数, 对于LASTSAVE
是UNIX时间等等. 但是, 返回的整数保证位于有符号的64位整数范围内.
Integers
回复也广泛用于返回true
或false
。例如像 EXISTS
或 SISMEMBER
这样的命令将返回1为真,0为假.
其他命令如 SADD
, SREM
和 SETNX
将在实际执行操作时返回1, 否则返回0.
以下命令将回复一个整数回复: SETNX
, DEL
, EXISTS
, INCR
, INCRBY
, DECR
, DECRBY
, DBSIZE
, LASTSAVE
, REINENX
, MOVE
, LLEN
, SADD
,SREM
, SISMEMBER
, SCARD
.
RESP Bulk Strings
Bulk Strings
用于表示长达512 MB的单个二进制安全的字符串.
Bulk Strings
按以下方式编码:
- 一个以“$”字节开始,后面是组成字符串的字节数(前缀长度),由CRLF终止.
- 实际的字符串数据.
- 最后的CRLF.
所以字符串"foobar"被编码成如面:
"$6\r\nfoobar\r\n"
空字符串:
"$0\r\n\r\n"
RESP Bulk Strings
也能用特殊的格式来表示Null
值,一个不存在的值.在这种特殊的格式中, 长度是-1, 并且没有数据,所以空值表示为:
"$-1\r\n"
这被称为Null Bulk String
.
当服务器使用Null Bulk String
回复时,客户端库API不应该返回空字符串, 而是返回一个nil对象. 例如, Ruby库应该返回’nil’, 而C库应该返回NULL值(或者在应答对象中设置一个特殊的标志),等等.
RESP Arrays
Redis客户端使用RESP数组发送命令到Redis服务器.同样,某些Redis命令使用 RESP数组 作为回复类型 将元素集合返回给客户端. 一个例子是返回列表元素的LRANGE
命令.
RESP数组使用以下格式发送:
- 一个"*"字符作为第一个字节,后面跟着一个十进制的数字,表示数组中元素的个数,然后是CRLF
- Array的每个元素都有一个额外的RESP类型
所以一个空的Array只是以下内容:
"*0\r\n"
在有两个RESP Bulk Strings
内容为“foo”和“bar”的数组中编码为:
"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"
As you can see after the *CRLF part prefixing the array, the other data types composing the array are just concatenated one after the other. For example an Array of three integers is encoded as follows:
正如你所看到的*<count>CRLF
部分作为数组前缀,组成数组的其他数据类型只是依次连接在一起. 例如, 一个包含三个整数的数组编码如下:
"*3\r\n:1\r\n:2\r\n:3\r\n"
数组可以包含混合类型,元素之间不必是同一类型的.例如,一个四个整数和一个字符串块的列表可以编码如下:
*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n
(为了清楚起见,应答内容分为多行).
服务器发送的第一行是 *5\r\n, 以指定接下来的五个回复. 然后,构成多批量回复的项目的每个回复都被传送.
Null数组的概念也存在,并且是指定Null值的替代方法(通常使用Null Bulk String
,但由于历史原因,我们有两种格式)
例如, 当命令BLPOP
超时时, 它会返回一个空数组, 其计数为-1, 如下例所示:
"*-1\r\n"
当Redis使用空数组响应时,客户端库API应返回空对象而不是空数组. 这是区分empty list
和不同条件(例如命令BLPOP的超时条件)所必需的.
在RESP协议中也有可能存在数组的数组. 例如,两个数组的数组编码如下:
*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n
(回复内容被分成多行,并加了空行,只是为了阅读方便).
上述RESP数据类型的编码表示了一个包含两个数组元素的数组,一个是包含三个整数1,2,3的一个数组,另一个是包含一个简单字符串和一个错误组成的两个元素的数组.
Arrays中的Null元素 (Null elements in Arrays)
数组中的单个元素可能为空. 这用于Redis回复中,以表示这些元素缺失并且不是空的字符串. 当SORT
命令使用GET模式选项时,如果缺少指定的键,可能会发生这种情况. 包含Null
元素的Array
回复的示例:
*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n
第二个元素是Null
.客户端库应该返回如下所示的内容:
["foo",nil,"bar"]
类似于PHP中 {“foo”, null, “bar”} 这样的数组.
请注意,这不是前面章节中所述的异常情况,而只是进一步指定协议的一个示例.
将命令发送到Redis服务器 (Sending commands to a Redis Server)
现在对RESP序列化格式已经熟悉,编写Redis客户端库的实现将变得很容易.我们可以进一步指定客户端和服务器之间的交互如何工作:
- 客户端向Redis服务器发送仅包含Bulk Strings的RESP数组
- Redis服务器回复以任何有效的RESP数据类型作为客户端的答复
例如,一个典型的交互可能是如下这样.
客户端发送命令 LLEN mylist
以获取存储在键名为mylist中的列表的长度,并且服务器以如下例子回复一个整数应答(C:是客户端, S:服务器).
C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n
S: :48293\r\n
通常我们将协议的不同部分用换行符分开,但实际的交互是客户端作为一个整体发送 *2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n
多个命令和管道 (Multiple commands and pipelining)
客户端可以使用相同的连接来发出多个命令。支持管道操作,因此客户端可以使用单个写入操作发送多个命令,而无需在发出下一条命令之前读取先前命令的服务器回复。所有的答复都可以在最后阅读.
更多信息,请查看我们page about Pipelining.
内联命令 (Inline Commands)
有时你手中只有telnet
工具,并且你需要发送一个命令到Redis服务器. 虽然Redis协议易于实现,但在交互式会话中使用并不理想,而redis-cli可能并不总是可用. 出于这个原因, Redis也以一种专门为人类设计的方式接受命令,并被称为内联命令(inline command
)格式.
下面是个 server/client 使用内联命令通信的例子(server以S开头,client以C开头):
C: PING
S: +PONG
以下是返回整数的内联命令的另一个示例:
C: EXISTS somekey
S: :0
基本上你只需在telnet会话中编写空格分隔的参数. 由于没有以统一请求协议中使用的 *
开始的命令, Redis 能够探测到这种情况并解析您的命令.
Redis协议的高性能分析器 (High performance parser for the Redis protocol)
尽管Redis协议非常易于人阅读同时易实现,但它也可以通过类似二进制协议的性能来实现.
RESP使用前缀长度来传输大块数据,因此从不需要为了有效负载而扫描特殊字符(例如在JSON上存在的情况),也不需要引用发送到服务器的有效负载.
批量和多批量的长度可以使用代码进行计算,每个字符执行一次计算操作,同时扫描CR字符检查,像下面的C代码一样.
#include <stdio.h>
int main(void) {
unsigned char *p = "$123\r\n";
int len = 0;
p++;
while(*p != '\r') {
len = (len*10)+(*p - '0');
p++;
}
/* Now p points at '\r', and the len is in bulk_len. */
printf("%d\n", len);
return 0;
}
在识别出第一个CR之后,可以在不进行任何处理的情况下将其与以下LF一起跳过. 然后可以使用单个读取操作读取批量数据,该操作不会以任何方式检查有效负载. 最后,剩余的 CR 和 LF 字符将被丢弃而不进行任何处理.
Redis协议有可与二进制协议相比的性能,同时显著简化了在高级语言中的实现,减少在实现客户端软件中的错误数量.
为了避免原文因为更新出现不一致,故保留原文.
原文链接
原文
Redis Protocol specification
Redis clients communicate with the Redis server using a protocol called RESP (REdis Serialization Protocol). While the protocol was designed specifically for Redis, it can be used for other client-server software projects.
RESP is a compromise between the following things:
Simple to implement.
Fast to parse.
Human readable.
RESP can serialize different data types like integers, strings, arrays. There is also a specific type for errors. Requests are sent from the client to the Redis server as arrays of strings representing the arguments of the command to execute. Redis replies with a command-specific data type.
RESP is binary-safe and does not require processing of bulk data transferred from one process to another, because it uses prefixed-length to transfer bulk data.
Note: the protocol outlined here is only used for client-server communication. Redis Cluster uses a different binary protocol in order to exchange messages between nodes.
Networking layer
A client connects to a Redis server creating a TCP connection to the port 6379.
While RESP is technically non-TCP specific, in the context of Redis the protocol is only used with TCP connections (or equivalent stream oriented connections like Unix sockets).
Request-Response model
Redis accepts commands composed of different arguments. Once a command is received, it is processed and a reply is sent back to the client.
This is the simplest model possible, however there are two exceptions:
Redis supports pipelining (covered later in this document). So it is possible for clients to send multiple commands at once, and wait for replies later.
When a Redis client subscribes to a Pub/Sub channel, the protocol changes semantics and becomes a push protocol, that is, the client no longer requires sending commands, because the server will automatically send to the client new messages (for the channels the client is subscribed to) as soon as they are received.
Excluding the above two exceptions, the Redis protocol is a simple request-response protocol.
RESP protocol description
The RESP protocol was introduced in Redis 1.2, but it became the standard way for talking with the Redis server in Redis 2.0. This is the protocol you should implement in your Redis client.
RESP is actually a serialization protocol that supports the following data types: Simple Strings, Errors, Integers, Bulk Strings and Arrays.
The way RESP is used in Redis as a request-response protocol is the following:
Clients send commands to a Redis server as a RESP Array of Bulk Strings.
The server replies with one of the RESP types according to the command implementation.
In RESP, the type of some data depends on the first byte:
For Simple Strings the first byte of the reply is “+”
For Errors the first byte of the reply is “-”
For Integers the first byte of the reply is “:”
For Bulk Strings the first byte of the reply is “$”
For Arrays the first byte of the reply is “*”
Additionally RESP is able to represent a Null value using a special variation of Bulk Strings or Array as specified later.
In RESP different parts of the protocol are always terminated with “\r\n” (CRLF).
RESP Simple Strings
Simple Strings are encoded in the following way: a plus character, followed by a string that cannot contain a CR or LF character (no newlines are allowed), terminated by CRLF (that is “\r\n”).
Simple Strings are used to transmit non binary safe strings with minimal overhead. For example many Redis commands reply with just “OK” on success, that as a RESP Simple String is encoded with the following 5 bytes:
“+OK\r\n”
In order to send binary-safe strings, RESP Bulk Strings are used instead.
When Redis replies with a Simple String, a client library should return to the caller a string composed of the first character after the ‘+’ up to the end of the string, excluding the final CRLF bytes.
RESP Errors
RESP has a specific data type for errors. Actually errors are exactly like RESP Simple Strings, but the first character is a minus ‘-’ character instead of a plus. The real difference between Simple Strings and Errors in RESP is that errors are treated by clients as exceptions, and the string that composes the Error type is the error message itself.
The basic format is:
“-Error message\r\n”
Error replies are only sent when something wrong happens, for instance if you try to perform an operation against the wrong data type, or if the command does not exist and so forth. An exception should be raised by the library client when an Error Reply is received.
The following are examples of error replies:
-ERR unknown command ‘foobar’
-WRONGTYPE Operation against a key holding the wrong kind of value
The first word after the “-”, up to the first space or newline, represents the kind of error returned. This is just a convention used by Redis and is not part of the RESP Error format.
For example, ERR is the generic error, while WRONGTYPE is a more specific error that implies that the client tried to perform an operation against the wrong data type. This is called an Error Prefix and is a way to allow the client to understand the kind of error returned by the server without to rely on the exact message given, that may change over the time.
A client implementation may return different kind of exceptions for different errors, or may provide a generic way to trap errors by directly providing the error name to the caller as a string.
However, such a feature should not be considered vital as it is rarely useful, and a limited client implementation may simply return a generic error condition, such as false.
RESP Integers
This type is just a CRLF terminated string representing an integer, prefixed by a “:” byte. For example “:0\r\n”, or “:1000\r\n” are integer replies.
Many Redis commands return RESP Integers, like INCR, LLEN and LASTSAVE.
There is no special meaning for the returned integer, it is just an incremental number for INCR, a UNIX time for LASTSAVE and so forth. However, the returned integer is guaranteed to be in the range of a signed 64 bit integer.
Integer replies are also extensively used in order to return true or false. For instance commands like EXISTS or SISMEMBER will return 1 for true and 0 for false.
Other commands like SADD, SREM and SETNX will return 1 if the operation was actually performed, 0 otherwise.
The following commands will reply with an integer reply: SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.
RESP Bulk Strings
Bulk Strings are used in order to represent a single binary safe string up to 512 MB in length.
Bulk Strings are encoded in the following way:
A “$” byte followed by the number of bytes composing the string (a prefixed length), terminated by CRLF.
The actual string data.
A final CRLF.
So the string “foobar” is encoded as follows:
“$6\r\nfoobar\r\n”
When an empty string is just:
“$0\r\n\r\n”
RESP Bulk Strings can also be used in order to signal non-existence of a value using a special format that is used to represent a Null value. In this special format the length is -1, and there is no data, so a Null is represented as:
“$-1\r\n”
This is called a Null Bulk String.
The client library API should not return an empty string, but a nil object, when the server replies with a Null Bulk String. For example a Ruby library should return ‘nil’ while a C library should return NULL (or set a special flag in the reply object), and so forth.
RESP Arrays
Clients send commands to the Redis server using RESP Arrays. Similarly certain Redis commands returning collections of elements to the client use RESP Arrays are reply type. An example is the LRANGE command that returns elements of a list.
RESP Arrays are sent using the following format:
A * character as the first byte, followed by the number of elements in the array as a decimal number, followed by CRLF.
An additional RESP type for every element of the Array.
So an empty Array is just the following:
“*0\r\n”
While an array of two RESP Bulk Strings “foo” and “bar” is encoded as:
“*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n”
As you can see after the *CRLF part prefixing the array, the other data types composing the array are just concatenated one after the other. For example an Array of three integers is encoded as follows:
“*3\r\n:1\r\n:2\r\n:3\r\n”
Arrays can contain mixed types, it’s not necessary for the elements to be of the same type. For instance, a list of four integers and a bulk string can be encoded as the follows:
*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n
(The reply was split into multiple lines for clarity).
The first line the server sent is *5\r\n in order to specify that five replies will follow. Then every reply constituting the items of the Multi Bulk reply are transmitted.
The concept of Null Array exists as well, and is an alternative way to specify a Null value (usually the Null Bulk String is used, but for historical reasons we have two formats).
For instance when the BLPOP command times out, it returns a Null Array that has a count of -1 as in the following example:
“*-1\r\n”
A client library API should return a null object and not an empty Array when Redis replies with a Null Array. This is necessary to distinguish between an empty list and a different condition (for instance the timeout condition of the BLPOP command).
Arrays of arrays are possible in RESP. For example an array of two arrays is encoded as follows:
*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n
(The format was split into multiple lines to make it easier to read).
The above RESP data type encodes a two elements Array consisting of an Array that contains three Integers 1, 2, 3 and an array of a Simple String and an Error.
Null elements in Arrays
Single elements of an Array may be Null. This is used in Redis replies in order to signal that these elements are missing and not empty strings. This can happen with the SORT command when used with the GET pattern option when the specified key is missing. Example of an Array reply containing a Null element:
*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n
The second element is a Null. The client library should return something like this:
[“foo”,nil,“bar”]
Note that this is not an exception to what was said in the previous sections, but just an example to further specify the protocol.
Sending commands to a Redis Server
Now that you are familiar with the RESP serialization format, writing an implementation of a Redis client library will be easy. We can further to specify how the interaction between the client and the server works:
A client sends the Redis server a RESP Array consisting of just Bulk Strings.
A Redis server replies to clients sending any valid RESP data type as reply.
So for example a typical interaction could be the following.
The client sends the command LLEN mylist in order to get the length of the list stored at key mylist, and the server replies with an Integer reply as in the following example (C: is the client, S: the server).
C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n
S: :48293\r\n
As usual we separate different parts of the protocol with newlines for simplicity, but the actual interaction is the client sending *2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n as a whole.
Multiple commands and pipelining
A client can use the same connection in order to issue multiple commands. Pipelining is supported so multiple commands can be sent with a single write operation by the client, without the need to read the server reply of the previous command before issuing the next one. All the replies can be read at the end.
For more information please check our page about Pipelining.
Inline Commands
Sometimes you have only telnet to hand and you need to send a command to the Redis server. While the Redis protocol is simple to implement it is not ideal to use in interactive sessions, and redis-cli may not always be available. For this reason Redis also accepts commands in a special way that is designed for humans, and is called the inline command format.
The following is an example of a server/client chat using an inline command (the server chat starts with S:, the client chat with C:)
C: PING
S: +PONG
The following is another example of an inline command returning an integer:
C: EXISTS somekey
S: :0
Basically you simply write space-separated arguments in a telnet session. Since no command starts with * that is instead used in the unified request protocol, Redis is able to detect this condition and parse your command.
High performance parser for the Redis protocol
While the Redis protocol is very human readable and easy to implement it can be implemented with a performance similar to that of a binary protocol.
RESP uses prefixed lengths to transfer bulk data, so there is never a need to scan the payload for special characters like it happens for instance with JSON, nor to quote the payload that needs to be sent to the server.
The Bulk and Multi Bulk lengths can be processed with code that performs a single operation per character while at the same time scanning for the CR character, like the following C code:
#include <stdio.h>
int main(void) {
unsigned char *p = “$123\r\n”;
int len = 0;
p++;
while(*p != '\r') {
len = (len*10)+(*p - '0');
p++;
}
/* Now p points at '\r', and the len is in bulk_len. */
printf("%d\n", len);
return 0;
}
After the first CR is identified, it can be skipped along with the following LF without any processing. Then the bulk data can be read using a single read operation that does not inspect the payload in any way. Finally the remaining the CR and LF character are discarded without any processing.
While comparable in performance to a binary protocol the Redis protocol is significantly simpler to implement in most very high level languages, reducing the number of bugs in client software.
CRLF,是 Carriage-Return Line-Feed 的缩写,CR就是回车"\r",LF就是换行"\n". ↩︎