Write Redis client by yourself-Redis protocol (1), redis Client
Network Layer
The client interacts with the server over TCP connections. The default port number of the server is 6379.
All commands or data sent by the client and server end with \ r \ n (CRLF.
Request
The Redis Server accepts commands and command parameters.
After receiving the command, the server processes the command and sends the command response back to the client.
New unified request protocol
The new unified request protocol was introduced in Redis 1.2 and eventually became the standard communication mode for Redis servers in Redis 2.0.
Your Redis client should follow the new protocol.
In this Protocol, all parameters sent to the Redis server are binary safe.
The following is the general form of this Protocol:
* <Number of parameters> CR LF
$ <Number of bytes for parameter 1> CR LF
<Data of parameter 1> CR LF
...
$ <Number of bytes of parameter N> CR LF
<Data of parameter N> CR LF
Annotation: The command itself is also sent as one of the parameters of the protocol.
For example, here is a printed version of the command protocol:
* 3
$ 3
SET
$ 5
mykey
$ 7
myvalue
The actual protocol value of this command is as follows:
"* 3 \ r \ n $ 3 \ r \ nSET \ r \ n $ 5 \ r \ nmykey \ r \ n $ 7 \ r \ nmyvalue \ r \ n"
As we will see later, in addition to being used as a command request protocol, this format is also used in command reply protocols: This one-parameter reply format is called Bulk Reply.
The unified protocol request was originally used in the reply protocol to return multiple items of the list to the client. This reply format is called Multi Bulk Reply.
A multiple batch response is prefixed with * <argc> \ r \ n, followed by multiple different batch responses, where argc is the number of these batch responses.
Reply
Redis commands return many different types of replies.
By examining the first byte of data sent back by the server, you can determine what type of response this is:
The first byte of the status reply is "+"
The first byte of the error reply is "-"
The first byte of an integer reply is ":"
The first byte of a bulk reply is "$"
The first byte of a multi bulk reply is "*"
Status reply
A status reply (or single line reply) is a single line string that starts with "+" and ends with "\ r \ n".
The following is an example of a status reply:
+ OK
The client library should return everything after the "+" sign. For example, in the above example, the client should return the string "OK".
Status replies are usually returned by commands that do not need to return data. Such replies are not binary-safe and cannot contain new lines.
The overhead of status reply is very small, it only needs three bytes ("+" at the beginning and CRLF at the end).
Error reply
Error replies are very similar to status replies. The only difference between them is that the first byte of an error reply is "-" and the first byte of a status reply is "+".
Error replies are only sent when something goes wrong: for example, when a user executes a command on an incorrect data type, or executes a command that does not exist, and so on.
A client library should generate an exception when receiving an error response.
Here are two examples of error responses:
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value
After the "-", until the first space or new behavior is encountered, the content in the middle indicates the type of error returned.
ERR is a general error, while WRONGTYPE is a more specific error. A client implementation can generate different types of exceptions for different types of errors, or provide a general way for callers to trap different errors by providing the error names in the form of strings.
However, these features are not used much, so it is not particularly important. A limited client can indicate a general error condition by simply returning a logical false.
Integer reply
An integer reply is an integer represented by a string beginning with ":" and ending with CRLF.
For example, ": 0 \ r \ n" and ": 1000 \ r \ n" are integer responses.
Two of the commands that return integer responses are INCR and LASTSAVE. The returned integer has no special meaning, INCR returns an incremented integer value of the key, and LASTSAVE returns a UNIX timestamp. The only limitation of the returned value is that these numbers must be able to be represented by 64-bit signed integers.
Integer replies are also widely used to represent logical truth and logical false: for example, EXISTS and SISMEMBER both use a return value of 1 to represent true and 0 to represent false.
Other commands, such as SADD, SREM, and SETNX, return 1 only when the operation is actually executed, otherwise return 0.
The following commands all return integer responses: SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.
Bulk reply
The server uses a batch reply to return a binary-safe string with a maximum length of 512 MB.
Client: GET mykey
Server: foobar
In the content sent by the server:
The first byte is the "$" sign
Followed by a numeric value representing the actual reply length
Followed by a CRLF
Followed by the actual response data
At the end is another CRLF
For the previous GET command, what the server actually sent was:
"$ 6 \ r \ nfoobar \ r \ n"
If the requested value does not exist, the batch reply will use the special value -1 as the length value of the reply, like this:
Client: GET non-existing-key
Server: $ -1
This reply is called a NULL Bulk Reply.
When the request object does not exist, the client should return an empty object instead of an empty string: for example, the Ruby library should return nil, the C library should return NULL (or set a special flag in the reply object), and so on.
Multiple bulk replies
Commands like LRANGE need to return multiple values, and this goal can be accomplished with multiple batch replies.
Multiple batch responses are an array of multiple responses, and each element in the array can be any type of response, including multiple batch responses themselves.
The first byte of multiple batch replies is "*" followed by an integer value represented by a string. This value records the number of replies contained in multiple batch replies, followed by a CRLF.
Client: LRANGE mylist 0 3
Server: * 4
Server: $ 3
Server: foo
Server: $ 3
Server: bar
Server: $ 5
Server: Hello
Server: $ 5
Server: World
In the above example, all strings sent by the server end with CRLF.
As you can see, the format of multiple batch replies is exactly the same as the format of the unified request protocol used when the client sends commands. The only differences between them are:
The unified request protocol only sends batch responses.
Multiple batch replies sent by the server when responding to a command can include any type of reply.
The following example shows a batch response with four integer values and a binary secure string:
* 5 \ r \ n
: 1 \ r \ n
: 2 \ r \ n
: 3 \ r \ n
: 4 \ r \ n
$ 6 \ r \ n
foobar \ r \ n
In the first line of the response, the server sends * 5 \ r \ n, which means that this multiple batch response contains 5 responses, followed by the body of the 5 responses.
Multiple batch replies can also be empty, like this:
Client: LRANGE nokey 0 1
Server: * 0 \ r \ n
A null multi bulk reply also exists. For example, when the blocking time of the BLPOP command exceeds the maximum time limit, it returns a multiple bulk reply with no content. The count value of this reply is -1:
Client: BLPOP key 1
Server: * -1 \ r \ n
The client library should distinguish between multiple blank responses and multiple blank responses: When Redis returns a multiple blank response, the client library should return a null object instead of an empty array.
Empty elements in multiple batch replies
An element in multiple batch replies can set its length to -1, which means that the element does not exist and is not an empty string.
When the SORT command uses a GET pattern option to operate on a key that does not exist, multiple batch responses with blank elements can occur.
The following example shows a multiple batch response with empty elements:
Server: * 3
Server: $ 3
Server: foo
Server: $ -1
Server: $ 3
Server: bar
Among them, the second element in the reply is empty.
For this response, the client library should return a response similar to this:
["foo", nil, "bar"]
Multi-command and pipeline
The client can send multiple commands in one write operation through the pipeline:
It is not necessary to read the reply to the previous command before sending a new command.
Responses to multiple commands are returned at the end.
Inline command
When you need to communicate with the Redis server, but cannot find redis-cli, and you only have telnet, you can send commands through Redis's inline command format specially designed for this situation.
The following is an example of client and server interaction using inline commands:
Client: PING
Server: + PONG
Here is another example of an inline command that returns an integer value:
Client: EXISTS somekey
Server:: 0
Because there is no "*" item in the unified request protocol to declare the number of parameters, when entering commands in a telnet session, each parameter must be separated by a space. After receiving the data, the server will perform user input by space Parse and get the command parameters.
High-performance Redis protocol analyzer
Although the Redis protocol is very human-readable and the definition is simple, the implementation performance of this protocol can still be as fast as the binary protocol.
Because the Redis protocol puts the length of the data before the data body, the program does not need to scan the entire payload in order to find a special character like JSON, nor does it need to escape the payload sent to the server (quote).
The program can process the characters in the protocol text, find the CR characters, and calculate the length of the batch response or multiple batch responses, like this:
#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 obtaining the length of the batch reply or multiple batch replies, the program only needs to call the read function once to read all the body data of the reply into the memory without any processing on the data.
CR and LF at the end of the reply are not processed, they are discarded.
The implementation performance of the Redis protocol can be comparable to that of the binary protocol, and due to the simplicity of the Redis protocol, most high-level languages can easily implement this protocol, which greatly reduces the number of bugs in client software.