RESP協議官網:https://redis.io/topics/protocol
RESP協議中文官網:http://www.redis.cn/topics/protocol.html
本文代碼對應的github地址:https://github.com/nieandsun/redis-study
1 RESP協議簡介
RESP( REdis Serialization Protocol) 是Redis客戶端與Redis服務器間進行通訊的協議。其主要特點如下:
- 容易實現
- 解析快
- 人類可讀
RESP 底層採用的是 TCP 的連接方式, 通過 tcp 進行數據傳輸, 然後根據解析規則解析相應信息, 完成交互。
我們可以測試下, 首先運行一個 serverSocket 監聽 6379, 來接收 redis 客戶端的請求信息, 實現如下:
//模擬redis服務器
public class ServerRedis {
public static void main(String[] args) {
try {
//監聽6379端口
ServerSocket serverSocket = new ServerSocket(6379);
Socket rec = serverSocket.accept();
byte[] result = new byte[2048];
rec.getInputStream().read(result);
System.out.println(new String(result));
} catch (IOException e) {
e.printStackTrace();
}
}
}
再通過redis的客戶端jedis給6379端口發送請求:
public class ClientRedis {
/***
* 使用redis客戶端jedis給6379端口發送消息
* @param args
*/
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.set("name", "lisonLength");
jedis.close();
}
}
測試發現,服務端打印的信息如下:
這就是Resp協議的結構 — 》 AOF存儲的就是這些命令,有興趣的可以回看一下我的文章《【redis知識點整理】 — Redis的持久化》。
2 自己手寫一個簡單的redis客戶端
1中可以看到,其實Jedis就是將我們的key 和 Value拼裝成滿足RESP協議的字符串通過Socket發送給了Redis服務器來完成與Redis服務器的交互。
這時候我們肯定會想,假如我們自己按照RESP的規範,拼裝一個字符串,然後通過Socket發送給redis服務器,能不能完成存儲和查詢呢???
其實是可以的,舉例如下:
package com.nrsc.redis.learning.resp;
import java.io.IOException;
import java.net.Socket;
public class SelfRedisClient {
/*
*3
$3
SET
$4
name
$6
rehash
*/
public static String set(Socket socket, String key, String value) throws IOException {
//按照RESP協議拼接字符串
StringBuffer str = new StringBuffer();
str.append("*3").append("\r\n");
str.append("$3").append("\r\n");
str.append("SET").append("\r\n");
str.append("$").append(key.getBytes().length).append("\r\n");
str.append(key).append("\r\n");
str.append("$").append(value.getBytes().length).append("\r\n");
str.append(value).append("\r\n");
socket.getOutputStream().write(str.toString().getBytes());
byte[] response = new byte[2048];
socket.getInputStream().read(response);
return new String(response);
}
/*
*2
$3
GET
$4
name
*/
public static String get(Socket socket, String key) throws IOException {
//按照RESP協議拼接字符串
StringBuffer str = new StringBuffer();
str.append("*2").append("\r\n");
str.append("$3").append("\r\n");
str.append("GET").append("\r\n");
str.append("$").append(key.getBytes().length).append("\r\n");
str.append(key).append("\r\n");
socket.getOutputStream().write(str.toString().getBytes());
byte[] response = new byte[2048];
socket.getInputStream().read(response);
return new String(response);
}
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 6379);
String set = set(socket, "shaka", "loveStus");
System.out.println(set);
System.out.println(get(socket, "shaka"));
}
}
測試結果如下,可以看到用我們自己寫的客戶端確實可以與redis服務器進行交互,完成存儲和讀取數據。
end!!!