RESP Protocol#
Redis is a software with a CS architecture, 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 result to the client.
Therefore, the format of the command sent by the client and the format of the response result from the server must have a specification, and this specification 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 protocol 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 end.
The array type actually looks quite similar to the AOF file.
Simulating 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 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 should read len bytes, but it has been converted to character stream, so assume no special characters exist
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 using 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