当前位置:网站首页>Redis通信协议--RESP协议
Redis通信协议--RESP协议
2022-07-28 02:37:00 【三月不灭】
Redis通信协议–RESP协议
Redis是一个CS架构的软件,通信一般分两步(不包括pipeline和PubSub) :
1)客户端(client)向服务端( server)发送一条命令
2)服务端解析并执行命令,返回响应结果给客户端
因此客户端发送命令的格式、服务端响应结果的格式必须有一个规范,这个规范就是通信协议。
而在Redis中采用的是RESP ( Redis Serialization Protocol)协议:
- Redis 1.2版本引入了RESP协议
- Redis 2.0版本中成为与Redis服务端通信的标准,称为RESP2
- Redis 6.0版本中,从RESP2升级到了RESP3协议,增加了更多数据类型并且支持6.0的新特性–客户端缓存
但目前,默认使用的依然是RESP2协议,也是我们要学习的协议版本(以下简称RESP)。
REPS协议:客户端在向服务端发送命令时或者服务端向客户端返回的结果,遵从一定的规范
RESP协议-数据类型
在RESP中,通过首字节的字符来区分不同数据类型,常用的数据类型包括5种:
单行字符串:首字节是’+',后面跟上单行字符串,以CRLF (“\r\n”)结尾。例如返回"OK":—>“+OK\r\n”
错误(Errors)∶首字节是’-',与单行字符串格式一样,只是字符串是异常信息,例如:“-Error message\r\n”
数值:首字节是’:',后面跟上数字格式的字符串,以CRLF结尾。例如: “:10\r\n”
多行字符串:首字节是‘$’,表示二进制安全的字符串,最大支持512MB:
- 如果大小为0,则代表空字符串:“$0\r\n\r\n”
- 如果大小为-1,则代表不存在:“$-1\r\n”
- 如果大小为5,则表示为:“$5\r\nhello\r\n”
数组:首字节是‘*’,后面跟上数组元素个数,再跟上元素,元素数据类型不限:
*3\r\n -->数组元素个数,下面三个都是数组元素
:10\r\n
$5\r\nhello\r\n
*2\r\n$3\r\nage\r\n"10\r\n
注意点:
单行字符串:字符串中不能有/r/n的特殊字符,读到/r/n就结束,一般单行字符串用在结果返回中
错误:若服务端出现错误,返回异常提示字符串
多行字符串:记录字符串长度,然后读取指定长度代表结束
数组:元素类型可以是上述任意一种
redis请求一般是一个数组,如set name sanyue 会被转成一个数组发给服务端解析
模拟redis客户端发送命令和解析数据
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class Main {
static Socket s;
static PrintWriter writer;
static BufferedReader reader;
public static void main(String[] args) {
try {
// 1.建立连接
String host = "192.168.150.101";
int port = 6379;
s = new Socket(host, port);
// 2.获取输出流、输入流
writer = new PrintWriter(new OutputStreamWriter(s.getOutputStream(), StandardCharsets.UTF_8));//tcp发送请求,就是向socket中发送数据,获取数据,也是从socket中获取
reader = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.UTF_8));//理应用字节流,但这里为了方便用字符流,按行读
// 3.发出请求
// 3.1.获取授权 auth 123321
sendRequest("auth", "123456");//redis设置了密码就要授权
Object obj = handleResponse();
System.out.println("obj = " + obj);
// 3.2.set name 三月
sendRequest("set", "name", "三月");
// 4.解析响应
obj = handleResponse();
System.out.println("obj = " + obj);
// 3.2.set name 三月
sendRequest("get", "name");
// 4.解析响应
obj = handleResponse();
System.out.println("obj = " + obj);
// 3.2.set name 虎哥
sendRequest("mget", "name", "num", "msg");
// 4.解析响应
obj = handleResponse();
System.out.println("obj = " + obj);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5.释放连接
try {
if (reader != null) reader.close();
if (writer != null) writer.close();
if (s != null) s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 解析命令 set name sanyue
/**set name sanyue *3/r/n $3/r/nset/r/n $4/r/nname/r/n $/6/r/nsanyue/r/n */
private static void sendRequest(String ... args) {
writer.println("*" + args.length);//字符流println结尾会打印换行
for (String arg : args) {
writer.println("$" + arg.getBytes(StandardCharsets.UTF_8).length);
writer.println(arg);
}
writer.flush();
}
//解析命令
private static Object handleResponse() throws IOException {
// 读取首字节
int prefix = reader.read();
// 判断数据类型标示
switch (prefix) {
case '+': // 单行字符串,直接读一行
return reader.readLine();
case '-': // 异常,也读一行
throw new RuntimeException(reader.readLine());
case ':': // 数字
return Long.parseLong(reader.readLine());
case '$': // 多行字符串
// 先读长度
int len = Integer.parseInt(reader.readLine());
if (len == -1) {
return null;
}
if (len == 0) {
return "";
}
// 再读数据,读len个字节。我们假设没有特殊字符,所以读一行(简化)
return reader.readLine();
case '*':
return readBulkString();
default:
throw new RuntimeException("错误的数据格式!");
}
}
private static Object readBulkString() throws IOException {
// 获取数组大小
int len = Integer.parseInt(reader.readLine());
if (len <= 0) {
return null;
}
// 定义集合,接收多个元素
List<Object> list = new ArrayList<>(len);
// 遍历,依次读取每个元素
for (int i = 0; i < len; i++) {
list.add(handleResponse());
}
return list;
}
}
边栏推荐
- Where do I go to open an account for stock speculation? Is it safe to open an account on my mobile phone
- [QNX hypervisor 2.2 user manual]9.10 pass
- stm32F407-------DSP学习
- R 笔记 MICE
- Ci/cd from hardware programming to software platform
- STM32之IO模拟串口篇
- Stm32f407 ------- DSP learning
- Decision tree and random forest learning notes (1)
- The applet has obtained the total records and user locations in the database collection. How to use aggregate.geonear to arrange the longitude and latitude from near to far?
- Data Lake (XVII): Flink and iceberg integrate datastream API operations
猜你喜欢

Interview experience: first tier cities move bricks and face software testing posts. 5000 is enough

决策树与随机森林学习笔记(1)

数据湖:数据库数据迁移工具Sqoop

QML使用Layout布局时出现大量<Unknown File>: QML QQuickLayoutAttached: Binding loop detected for property循环绑定警告

exness:日本物价上涨收入下降,英镑/日元突破 165

Comprehensive comparative study of image denoising

每日刷题巩固知识

综合 案例

Distributed transaction Senta (I)

数据湖(十七):Flink与Iceberg整合DataStream API操作
随机推荐
每日刷题巩固知识
My approval of OA project (meeting inquiry & meeting signature)
机器人工程是否有红利期
Where do I go to open an account for stock speculation? Is it safe to open an account on my mobile phone
CAD creation group is not combined?
Interview experience: first tier cities move bricks and face software testing posts. 5000 is enough
【ACwing 1064 小国王】状压dp
对象数组转成strin再进行,隔开的字符串,包括赛选某个字段的子,或者求和,
The applet has obtained the total records and user locations in the database collection. How to use aggregate.geonear to arrange the longitude and latitude from near to far?
[QNX hypervisor 2.2 user manual]9.10 pass
【R语言】环境指定删除 rm函数
Blue Bridge Cup: the ninth - "lantern controller"
【类的本质(Objective-C语言中)】
从硬件编程到软件平台的ci/cd
将Helm编写的Chart推送到Harbor仓库
clientY vs pageY
C#WinForm开发:如何将图片添加到项目资源文件(Resources)中
4、 Analysis of solid state disk storage technology (paper)
【下载文件】uniapp开发小程序,下载文件并保存到本地
Promise object