RESP协议
RESP(即Redis Serialization Protocol)是Redis底层的通信协议。Redis客户端连接到Redis服务器,以创建与端口6379的TCP连接,通过RESP协议进行通信。
RESP 是基于请求-响应模型的。Redis接受由不同参数组成的命令。收到命令后,将对其进行处理并将答复发送回客户端。
但是有两个例外:
1、Redis支持管道模式(pipeline)。客户端可以一次发送多个命令,并在以后等待答复。
2、当Redis客户端订阅Pub / Sub通道时,该协议会更改语义并成为推送协议,也就是说,客户端不再需要发送命令,因为服务器会自动向客户端发送新消息(对于客户端的通道被订阅)。
除了上述两个例外,Redis协议是一种简单的请求-响应协议。
请求报文
get请求
get key1
对应的RESP协议报文:
*2
$3
get
$4
key1
其中
*2
表示有2个参数
$3
get
表示第1个参数长度为3,值为'get'
$4
key1
表示第2个参数长度为4,值为'key1'
set请求
set key1 value1
对应的RESP协议报文:
*3
$3
set
$4
key1
$6
value1
其中
*3
表示有3个参数
$3
set
表示第1个参数长度为3,值为'set'
$4
key1
表示第2个参数长度为4,值为'key1'
$6
value1
表示第3个参数长度为6,值为'value1'
类似的redis命令都可以通过这种格式生成请求报文。
响应报文
根据数据类型不同,响应报文的开头共有5种类型:
- 单行字符串 以 + 符号开头。
- 多行字符串 以 $ 符号开头,后跟字符串长度。
- 整数值 以 : 符号开头,后跟整数的字符串形式。
- 错误消息 以 - 符号开头。
- 数组 以 * 号开头,后跟数组的长度。
如:
+value1\r\n
表示字符串
-WRONGTYPE Operation against a key holding the wrong kind of value\r\n
表示错误消息
模拟Redis-Client
通过Socket模拟,传输RESP报文,来实现一个简单的get,set请求。
public static String get(Socket socket, String key) throws IOException {
StringBuffer str = new StringBuffer();
str.append("*2").append("\r\n");
str.append("$3").append("\r\n");
str.append("set").append("\r\n");
// key
str.append("$").append(key.getBytes().length).append("\r\n");
str.append(key).append("\r\n");
// 发送resp
socket.getOutputStream().write(str.toString().getBytes());
byte[] response = new byte[2048];
socket.getInputStream().read(response);
return new String(response);
}
public static String set(Socket socket, String key, String value) throws IOException {
StringBuffer str = new StringBuffer();
// 一共3个参数
str.append("*3").append("\r\n");
// 第一个set
str.append("$3").append("\r\n");
str.append("set").append("\r\n");
// key
str.append("$").append(key.getBytes().length).append("\r\n");
str.append(key).append("\r\n");
// value
str.append("$").append(value.getBytes().length).append("\r\n");
str.append(value).append("\r\n");
// 发送resp
socket.getOutputStream().write(str.toString().getBytes());
byte[] response = new byte[2048];
socket.getInputStream().read(response);
return new String(response);
}
以此类推,其他简单的Redis命令也能通过手写RESP来实现。