RESP Protocol#
Redis is a CS architecture software, and communication generally consists of two steps (excluding pipeline and PubSub):
- The client sends a command to the server.
- The server parses and executes the command, returning the response to the client.
Therefore, the format of the command sent by the client and the format of the response from the server must have a specification, which is the communication protocol.
RESP: Redis Serialization Protocol
Learn about the RESP2 protocol, which was introduced in version 2.0, and upgraded to RESP3 in 6.0, but due to significant changes, RESP2 is still used by default.
RESP Protocol Data Types#
For single-line strings, errors, and data, they are all binary unsafe. If \r\n is interspersed in the content, it may be misinterpreted as an ending.
The array type actually looks quite similar to the AOF file.
Simulating a Redis Client#
Is the reader not receiving information?
public class Main {
static Socket s;
static PrintWriter out;
static BufferedReader in;
public static void main(String[] args) {
try {
// 1. Establish connection
String host = "redis.orb.local";
int port = 6379;
s = new Socket(host, port);
// 2. Get input and output streams
out = new PrintWriter(
new OutputStreamWriter(s.getOutputStream(), StandardCharsets.UTF_8));
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 3. Send request and parse
// Get authorization auth TheBestWorkLoanapp1 sendRequest("auth", "TheBestWorkLoanapp1");
Object obj = handleResponse();
System.out.println(obj.toString());
// Set key-value pair set name Chanler sendRequest("set", "name", "Chanler");
obj = handleResponse();
System.out.println(obj.toString());
// Get key-value pair get name sendRequest("get", "name");
obj = handleResponse();
System.out.println(obj.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. Release connection
try {
if (s != null) {s.close();}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (out != null) {out.close();}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (in != null) {in.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static Object handleResponse() throws IOException {
// Read the first byte to determine the data type
int prefix = in.read();
switch (prefix) {
case '+':
return in.readLine();
case '-':
throw new RuntimeException(in.readLine());
case ':':
return Long.parseLong(in.readLine());
case '$':
int len = Integer.parseInt(in.readLine());
if (len == -1) {
return null;
}
if (len == 0) {
return "";
}
// Here it should read len bytes, but it has been converted to character stream, so assume there are no special characters
return in.readLine();
case '*':
return readBulkString();
default:
throw new RuntimeException("Invalid prefix");
}
}
private static Object readBulkString() throws IOException {
int len = Integer.parseInt(in.readLine());
if (len == 0) {
return null;
}
List<Object> list = new ArrayList<>();
for (int i=0; i<len; i++) {
list.add(handleResponse());
}
return list;
}
// Send set name Chanler
private static void sendRequest(String ... args) {
// \r\n is the newline character, here println directly includes it
out.println("*" + args.length);
for (String arg : args) {
out.println("$" + arg.getBytes(StandardCharsets.UTF_8).length);
out.println(arg);
}
out.flush();
}
}
This article is synchronized and updated to xLog by Mix Space
The original link is https://blog.0xling.cyou/posts/redis/redis-5