Preface
This article is very simple , Just write a Java Version of Redis Client, And it's not a production level project , It's just a validation type demo. Used to understand “ Achieve one Redis Client” What should I pay attention to .
reflection
-
First ,Redis It's a server , Yes ip, There are ports , that , We can use it Java Of Socket To interact with him , It can also be used. telnet To interact . To put it bluntly , It's just one. TCP The server , Just open it TCP passageway , And then make a connection 3 The second handshake , Set up a full duplex channel , You can send data to each other .
-
From our previous programming experience , That's true. , Interact with a server , It usually requires an agreement , for example HTTP The server , You need HTTP agreement , and Dubbo Interaction , You need to understand Dubbo agreement , Of course , These are all based on TCP Above the agreement . that ,Redis Maybe there is an agreement , Let's see later .
Hands on
Thinking about the two points above , We can try to do it .
We can use telnet Visit the following local Redis Server, for example :telnet 127.0.0.1 6379
, as follows :
* master telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^\]'.
set baby hello
+OK
get baby
$5
hello
del baby
:1
xxx
-ERR unknown command 'xxx'
step :
-
We're connected to the local Redis Server.
-
perform set baby hello command , That is to save a key value pair .
-
Back to +OK character string
-
And then we get the just baby character string .
-
Back to $5
Line break
hello -
And then we deleted baby character string .
-
Back to :1 ,1 Indicates that the deletion was successful .
-
Then we try to execute a command that doesn't exist .
-
Back to
-ERR unknown command 'xxx'
.
We use Redis Official redis-cli The client executes these commands and looks at the results :
* master redis-cli
127.0.0.1:6379> set baby hello
OK
127.0.0.1:6379> get baby
"hello"
127.0.0.1:6379> del baby
(integer) 1
127.0.0.1:6379> xxx
(error) ERR unknown command 'xxx'
127.0.0.1:6379>
Obviously ,redis-cli Client and telnet The difference between the use of the return value is the difference of the return value ,telnet There are some strange characters , Or in front of some return values, add some match , For example, in OK I added + Number . stay get baby after , Returned a $5 character string . We conjecture that ,telnet The data is Redis-Server The real data returned ,redis-cli These data are processed .
Okay , I have a general understanding of the operation , We use it Java Write a Socket Visit Redis Server.
use Java Socket visit Redis Server
The code is simple , as follows :
static Socket client = new Socket();
static InputStream is;
static OutputStream os;
static {
try {
client.connect(new InetSocketAddress("127.0.0.1", 6379));
is = client.getInputStream();
os = client.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
writeAndFlush("set baby hello \\n");
printResult();
// result : +OK
writeAndFlush("get baby \\n");
Sleep.sleep(1);// etc. redis Return the data
printResult();
// result : $5
// result : hello
writeAndFlush("del baby \\n");
Sleep.sleep(1);// etc. redis Return the data
printResult();
// result :1
writeAndFlush("xxx \\n");
Sleep.sleep(1);// etc. redis Return the data
printResult();
// -ERR unknown command \`xxx\`, with args beginning with:
writeAndFlush("mget hello baby \\r\\n");
Sleep.sleep(1);
printResult();
closeStream();
}
static void writeAndFlush(String content) {
try {
os.write(content.getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void closeStream() {
try {
is.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
static void printResult() {
try {
int a = is.available();
byte[] b = new byte[a];
is.read(b);
String result = new String(b);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
You can see , Use Java Socket And use telnet The effect is the same .
therefore , To achieve redis-cli The effect of , Then we need to process the return value , for example $5 、:1 These symbols , What does it mean ? namely : analysis redis Own application layer protocol .
Redis Serialization protocol (RESP)
The answer lies in redis Official documents of , Communication protocol protocol: http://redisdoc.com/topic/protocol.html)
redis The agreement calls it RESP(REdis Serialization Protocol), namely redis Serialization protocol .
The design objective of the protocol is :
-
Implement a simple .
-
Fast parsing .
-
Human readability .
All orders are in the form of \r\n
ending .
Redis After receiving the order , Processing commands , Then return the data .
redis 1.2 After version , Support batch reply :Buik Reply.
About reply , There are many types of :
By checking the first byte of data the server sends back , Can you determine what type of response this is :
-
State the reply (status reply) The first byte of
"+"
-
Error response (error reply) The first byte of
"-"
-
Integer reply (integer reply) The first byte of
":"
-
Batch reply (bulk reply) The first byte of
"$"
-
Multiple batch replies (multi bulk reply) The first byte of
"*"
We go back to our Socket In the app , You can see ,
-
When I perform
set
command , The return is+OK
, That is, this is the status reply . -
When we execute
xxx
command , The return value begins with - Number , This is the wrong reply . -
When we execute
get
command , The return is$5 hello
, This is a batch reply , meanwhile5
Indicates that it will return later 5 Bytes . The maximum length of a string is 512 MB. -
When we execute
del
command , The return is:1
, This is an integer reply , Only when the operation is actually executed , To return to1
, Otherwise return to 0, 1 Expresstrue
. -
When we execute
mget hello baby \r\n
when , The first character returned is * Number , It means that this is a batch reply .* The value after the sign records the number of multiple replies , What we're returning here is*2\r\n $5\r\n� world \r\n $-1\r\n
,*2
It means that there is 2 A reply .$5
It means that there is 5 Bytes .$-1
Expressbaby
Thiskey
There's no data ,-1
It means nothing .
Through the analysis of the agreement , We can make something like redis-cli The client of .
I'd like to introduce jade here , Wrote the simplest , Just look at it :)
public static void respParseHandler(String result) {
try {
if (result.startsWith("+")) {
// State the reply
System.out.println(result.substring(1));
return;
}
if (result.startsWith("-")) {
// Error response
System.err.println(result.substring(1));
return;
}
if (result.startsWith(":")) {
// Integer reply
if (result.substring(1).equalsIgnoreCase("1")) {
System.out.println("success");
} else {
System.out.println("error");
}
return;
}
if (result.startsWith("$")) {
// Batch reply
if (result.substring(1, 3).equalsIgnoreCase("-1")) {
System.out.println("no data, redis return -1");
return;
}
int line = result.indexOf("\\r\\n");
System.out.println(result.substring(line + 2));
return;
}
if (result.startsWith("*")) {
// Multiple batch replies
char num = result.charAt(1);
int first = result.indexOf('$');
for (int i = 0; i < Integer.valueOf(String.valueOf(num)); i++) {
int next = result.indexOf('$', first + 1);
if (next != -1) {
respParseHandler(result.substring(first, next));
} else {
respParseHandler(result.substring(first));
}
first = next;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
author : Mona Lu Road
link :https://www.jianshu.com/p/1aab4cbe4c3b
Recent hot article recommends :
1.Java 15 Official release , 14 A new feature , Refresh your mind !!
2. Finally, I got it through open source projects IntelliJ IDEA Activation code , It's delicious !
3. I use Java 8 Wrote a piece of logic , I can't understand it , You try ..
4. To hang up Tomcat ,Undertow It's very powerful !!
5.《Java Development Manual ( Song Mountain version )》 The latest release , Download it quickly !
I think it's good , Don't forget to like it + Forward !