当前位置:网站首页>实现基于Socket自定义的redis简单客户端
实现基于Socket自定义的redis简单客户端
2022-06-24 19:02:00 【枫蜜柚子茶】
一、RESP协议
首先需要明白,Redis是一个CS架构的软件,通信一般分两步(不包括pipeline和PubSub):
- 客户端(client)向服务端(server)发送一条命令
- 服务端解析并执行命令,返回响应结果给客户端 因此客户端发送命令的格式、服务端响应结果的格式必须有一个规范,这个规范就是通信协议。
而在Redis中采用的是RESP(Redis Serialization Protocol)协议:
- Redis 1.2版本引入了RESP协议
- Redis 2.0版本中成为与Redis服务端通信的标准,称为
- RESP2 Redis 6.0版本中,从RESP2升级到了RESP3协议,增加了更多数据类型并且支持6.0的新特性--客户端缓存
在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"

- 数组:首字节是 ‘*’,后面跟上数组元素个数,再跟上元素,元素数据类型不限:例如

二、模拟redis客户端实现
【响应解析请求模块】
/**
* 解析响应请求信息
*
* @return 解析结果
*/
private static Object handleResponse() throws IOException {
//五种情况读取数据
int opt = READER.read();
switch (opt) {
case '+'://单行字符串,读取单行信息
return READER.readLine();
case '-'://异常信息,读取单行信息返回异常
return READER.readLine();
case ':'://数值类型,读取单行
return Long.parseLong(READER.readLine());
case '*':
return readBulkString();
case '$'://读取多行字符串
int len = Integer.parseInt(READER.readLine());
if (len == -1) {
return null;
} else if (len == 0) {
return "";
} else {
return READER.readLine();
}
default:
throw new RuntimeException("错误的数据格式!");
}
}
/**
* 数组结果解析
*
* @return
* @throws IOException
*/
private static Object readBulkString() throws IOException {
//获取数组大小
int size = Integer.parseInt(READER.readLine());
if (size <= 0) {
return null;
} else {
List<Object> result = new ArrayList<>();
for (int i = 0; i < size; i++) {
result.add(handleResponse());
}
return result;
}
}【完整代码】
/**
* @Author 蜂蜜柚子茶
* @Date 2022/6/14 20:34
*/
public class MyRedisClient {
private static Socket socket;
private static PrintWriter WRITER;
private static BufferedReader READER;
private static BufferedReader KEYBOARD_INPUT;
private static final String INFO = "127.0.0.1:6379> ";
public static void main(String[] args) throws Exception {
try {
//建立连接
//虚拟机IP地址:192.168.29.128
socket = new Socket("192.168.29.128", 6379);
//获取输入流、输出流
WRITER = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
READER = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
//键盘输入命令
KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));
//执行命令,同时结果解析
execute();
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放连接
try {
if (READER != null)
READER.close();
if (WRITER != null)
WRITER.close();
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 获取键盘输入
*
* @return
* @throws Exception
*/
public static String getInput() throws Exception { // 键盘信息输入
System.out.print(INFO);
return KEYBOARD_INPUT.readLine();
}
/**
* 执行命令
*
* @throws IOException
*/
private static void execute() throws Exception {
while (true) {
//获取输入命令,去除首位空格
String string = getInput().trim();
//解析命令,去除所有空格
String replace = string.replaceAll("\\s{1,}", "/");
//System.out.println(replace);
String[] strings = replace.split("/");
//发送请求
sendRequest(strings);
//解析响应信息
Object result = handleResponse();
if (result == null) {
System.out.println(getFormatResult("null", "warning"));
} else if (result.toString().startsWith("ERR")) {
System.out.println(getFormatResult(result.toString(), "error"));
} else {
System.out.println(getFormatResult(result.toString(), "info"));
}
}
}
/**
* 格式化输出结果
*
* @param content 结果
* @param type 类型
* @return 格式化输出结果
*/
private static String getFormatResult(String content, String type) {
if (type.equals("error")) {
return String.format("\033[%dm%s\033[0m", 31, content);
} else if (type.equals("info")) {
return String.format("\033[%dm%s\033[0m", 34, content);
} else if (type.equals("warning")) {
return String.format("\033[%dm%s\033[0m", 33, content);
} else {
return content;
}
}
/**
* 解析响应请求信息
*
* @return 解析结果
*/
private static Object handleResponse() throws IOException {
//五种情况读取数据
int prefix = READER.read();
switch (prefix) {
case '+'://单行字符串,读取单行信息
return READER.readLine();
case '-'://异常信息,读取单行信息返回异常
return READER.readLine();
case ':'://数值类型,读取单行
return Long.parseLong(READER.readLine());
case '*':
return readBulkString();
case '$'://读取多行字符串
int len = Integer.parseInt(READER.readLine());
if (len == -1) {
return null;
} else if (len == 0) {
return "";
} else {
return READER.readLine();
}
default:
throw new RuntimeException("错误的数据格式!");
}
}
/**
* 数组结果解析
*
* @return
* @throws IOException
*/
private static Object readBulkString() throws IOException {
//获取数组大小
int size = Integer.parseInt(READER.readLine());
if (size <= 0) {
return null;
} else {
List<Object> result = new ArrayList<>();
for (int i = 0; i < size; i++) {
result.add(handleResponse());
}
return result;
}
}
/**
* 发送请求信息
*
* @param args
*/
private static void sendRequest(String... args) {
//本质上是命令--> set name XXXX
WRITER.println("*" + args.length);
for (String arg : args) {
WRITER.println("$" + arg.getBytes(StandardCharsets.UTF_8).length);
WRITER.println(arg);
}
//清空缓冲区
WRITER.flush();
}
}三、效果展示
【模拟redis-cli】idear窗口
win的控制台输出颜色乱码,不支持颜色的转义。

如果文章对你有用,狠狠地三连支持一下吧!!!
边栏推荐
- Full link service tracking implementation scheme
- What about the Golden Angel of thunder one? Golden Angel mission details
- 宅男救不了元宇宙
- Information theory of popular science Shannon
- Compressed list of redis data structures
- Steering gear control (stm32f103c8t6)
- [cann document express issue 04] unveiling the development of shengteng cann operator
- 华为云ModelArts第四次蝉联中国机器学习公有云服务市场第一!
- Drawing DEM with GEE gracefully
- 1、 Downloading and installing appium
猜你喜欢

Where are Xiaomi mobile phone's favorite SMS and how to delete them

Teach you how to view the number of connected people on WiFi in detail how to view the number of connected people on WiFi

16个优秀业务流程管理工具

Methods for comparing float types in the kernel

1、 Downloading and installing appium

Download steps of STM32 firmware library

Drawing DEM with GEE gracefully

php OSS文件讀取和寫入文件,workerman生成臨時文件並輸出瀏覽器下載

STM32 uses time delay to realize breathing lamp register version
![[video tutorial] functions that need to be turned off in win10 system. How to turn off the privacy option in win10 computer](/img/14/0313857adc178ecee4c866a05e54aa.jpg)
[video tutorial] functions that need to be turned off in win10 system. How to turn off the privacy option in win10 computer
随机推荐
[video tutorial] functions that need to be turned off in win10 system. How to turn off the privacy option in win10 computer
R for Data Science (note) -- data transformation (select basic use)
LCD12864 (ST7565P) Chinese character display (STM32F103)
Test drive citus 11.0 beta (official blog)
Five day summary of software testing
UART communication (STM32F103 library function)
字节、腾讯也下场,这门「月赚3000万」的生意有多香?
Teach you how to view the number of connected people on WiFi in detail how to view the number of connected people on WiFi
Volcano becomes spark default batch scheduler
Camera module and hardware interface of Camera1 camera
Digital twin industry case: Digital Smart port
How does the video platform import the old database into the new database?
Internet of things? Come and see Arduino on the cloud
Ribbon源码分析之@LoadBalanced与LoadBalancerClient
用自身细胞作为原料,首例3D打印耳朵移植成功!未来可打印更复杂器官
【CANN文档速递06期】初识TBE DSL算子开发
Understanding openstack network
Docker installing Oracle
Nodered has no return value after successfully inserting into the database (the request cannot be ended)
Zadig + cave Iast: let safety dissolve in continuous delivery