Redis通信协议

文章目录

  • Redis通信协议
    • RESP协议
      • 数据类型
    • 模拟Redis客户端

Redis通信协议

RESP协议

Redis是一个CS架构的软件,通信一般分为两步(不包含pipeline和PubSub):

  1. 客户端(client)向服务端(server)发送一条命令。
  2. 服务器解析并执行命令,返回响应结果到客户端。

因此,客户端发送命令好服务端响应结果的格式需要有一个规范(否则便无法正常通信),这个规范便是通信协议。

在Redis中采用的是RESP协议:

  • Redis1.2版本引入RESP协议。
  • Redis2.0版本中称为Redis服务通信的标准,成为REST2。
  • Redis6.0版本中,从RESP2升级到RESP3协议,增加了更多数据类型并且支持6.0的新特性(客户端缓存)。

但目前默认使用的依旧是RESP2协议,

数据类型

在RESP中,通过首字节的字符来区分不同数据类型,常用的数据类型包括5种:

  • 单行字符串:首字节是 ‘+’ ,后面跟上单行字符串,以CRLF( “\r\n” )结尾。例如返回"OK": “+OK\r\n”。

  • 错误(Errors):首字节是 ‘-’ ,与单行字符串格式一样,只是字符串是异常信息,例如:“-Error message\r\n”。

  • 数值:首字节是 ‘:’ ,后面跟上数字格式的字符串,以CRLF结尾。例如:“:10\r\n”。

  • 多行字符串:首字节是 ‘$’ ,表示二进制安全的字符串,最大支持512MB:

    image-20230604110955872

    • 如果大小为0,则代表空字符串:“$0\r\n\r\n”。
    • 如果大小为-1,则代表不存在:“$-1\r\n”
  • 数组:首字节是 ‘*****’,后面跟上数组元素个数,再跟上元素,元素数据类型不限:

    image-20230604111126867


模拟Redis客户端

Redis支持TCP通信,这里边使用Socket模拟客户端与Redis建立连接

public static void  RedisRequest(String address,String password,String...request) {Socket socket = null;PrintWriter writer = null;BufferedReader reader = null;try {// 1. 建立连接String host = address.substring(0,address.indexOf(":")); // redis的所在ip地址int port = Integer.parseInt(address.substring(address.indexOf(":") + 1)); //redis的端口号(默认6379)socket = new Socket(host, port);// 2. 获取输出流、输入流writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));// 获取授权(登录)if(password!=null && !"".equals(password)){sendRequest(writer,"auth "+password);}// 3. 发出请求 set name xiaomingsendRequest(writer,request);// 4. 解析响应(多次解析)for(int i = 0;i<request.length;i++){Object obj = handleResponse(reader);System.out.println(obj);}} catch (IOException e) {e.printStackTrace();} finally {// 5. 释放连接if(reader !=null){try {reader.close();} catch (IOException e) {e.printStackTrace();}}if(writer!=null){writer.close();}if(socket!=null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}
}

发送一条set命令和一条get命令(set name xiaoming , get name)

private static void sendRequest (PrintWriter writer,String...request) {String[][] req = new String[request.length][];for(int i = 0;i<request.length;i++){req[i] = request[i].split(" ");}for (String[] strings : req) {int n = strings.length;writer.println("*" + n);for (String s : strings) {writer.println("$" + s.getBytes(StandardCharsets.UTF_8).length);writer.println(s);}writer.flush();}
}

根据响应的类型来读取响应结果

private static Object handleResponse (BufferedReader reader) {// 读取首字节int prefix  = 0;try {prefix = reader.read();} catch (IOException e) {e.printStackTrace();}try {// 判断数据类型标示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;} else if (len == 0) {return "";}//读数据(这里使用的是字符流,直接读一行)return reader.readLine();}case '*' -> {return readbulkString(reader);}default -> throw new RuntimeException("错误的数据格式!");}} catch (IOException e) {e.printStackTrace();}return null;
}private static Object readbulkString (BufferedReader reader) {// 获取数据大小int len = 0;try {len = Integer.parseInt(reader.readLine());} catch (IOException e) {e.printStackTrace();}if(len <= 0){return null;}// 接收多个元素List<Object> list = new ArrayList<>(len);// 遍历,依次获取每个元素for(int i = 0;i < len;i++){list.add(handleResponse(reader));}return list;
}

使用单元测试方法,测试发送请求和接收响应

@Test
public void test(){Main.RedisRequest("192.168.45.138:6379",null,"set name xiaoming","get name");
}

测试结果为:

image-20230604160430155

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/54358.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面试题—2023年8月25日—PLKJ

2023年8月25日 北京 png ln kē j 答案仅供参考&#xff0c;博主仅记录发表&#xff0c;没有实际查询&#xff0c;不保证正确性。 面试题&#xff1a; 一.选择题 1.下面哪些是不合法的标识符 A.$persons B.TwoUsers C.*point D._endline 2. 下列语句执行后&#xff0c;k的值为…

Nginx 高级配置

目录 1 网页的状态页 2 Nginx 第三方模块 2.1 ehco 模块 3 变量 3.1 内置 3.2 定义变量 4 Nginx压缩功能 5 https 功能 6 自定义图标 1 网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http…

Mysql with as定义子查询

文章目录 1. 定义2. 适用场景3. 语法4. 示例 1. 定义 使用with as 可以让子查询重用相同的with查询块&#xff0c; 并在select查询块中直接引用&#xff0c; 一般用在select查询块会多次使用某个查询sql时&#xff0c; 会把这个sql语句放在with as 中&#xff0c; 作为公用的表…

基于PaddleOCR2.7.0发布WebRest服务测试案例

基于PaddleOCR2.7.0发布WebRest服务测试案例 #WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. #警告&#xff1a;这是一个开发服务器。不要在生产部署中使用它。请改用生产WSGI服务器。 输出结果…

我的128天创作纪念日-东离与糖宝

文章目录 机缘收获日常成就憧憬 不知不觉我也迎来了自己的128天创作纪念日&#xff0c;一起来看看我有什么想对大家说的吧 机缘 我的写博客之旅始于参加了代码随想录算法训练营。在训练营期间&#xff0c;代码随想录作者卡尔建议我们坚持每天写博客记录刷题学习的进度和心得体…

K8s学习笔记3

Kubernetes功能&#xff1a; Kubernetes是一个轻便的可扩展的开源平台&#xff0c;用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中&#xff0c;会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Goog…

【跟小嘉学 Rust 编程】十六、无畏并发(Fearless Concurrency)

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

stm32之USART(总结)

串行通信 UART串口内部结构示意图 普中科技的详细介绍 中断知识补充 代码 #ifndef __USART_H #define __USART_H #include "stdio.h" #include "stm32f10x_usart.h" #define USART1_REC_LEN 200 //定义最大接收字节数 200extern u8 USART1_RX_BUF[US…

排序算法:希尔排序

1959 年 7 月&#xff0c;美国辛辛那提大学的数学系博士 Donald Shell 在 《ACM 通讯》上发表了希尔排序算法&#xff0c;成为首批将时间复杂度降到 O(n)以下的算法之一。虽然原始的希尔排序最坏时间复杂度仍然是 O(n) &#xff0c;但经过优化的希尔排序可以达到 O(n1.3)甚至O(…

飞天使-k8s基础组件分析-服务与ingress

文章目录 服务的介绍服务代理服务发现连接集群外服务服务发布无头服务 服务&#xff0c;pod和dns的关系端口转发通过expose 暴露应用服务案例INGRESSMetalLB使用参考文档 服务的介绍 服务的作用是啥&#xff1f; 提供外部调用&#xff0c;保证podip的真实性看看服务解决了什么…

深入理解 Go 语言中的 iota

iota是go语言的常量计数器&#xff0c;只能在常量表达式中使用&#xff0c;iota在const关键字出现时将被重置为0&#xff0c;const中每新增一行常量声明将使iota计数一次&#xff0c;可理解为const语句块中的行索引。它会自动递增&#xff0c;从0开始。 修改步长 尽管默认步长…

淘宝商品数据采集(如何快速获取淘宝商品信息),淘宝API接口申请指南

淘宝作为国内的电商平台&#xff0c;拥有海量的商品信息。对于想要进行淘宝商品数据采集的人来说&#xff0c;如何快速获取淘宝商品信息是一个重要的问题。本文将介绍一些快速获取淘宝商品信息的方法。 1. 使用淘宝开放平台PI 淘宝开放平台提供了多种PI接口&#xff0c;可以通…

五公里场地训练笔记(完整版)

由于考研和口罩等原因&#xff0c;停跑了比较长的时间。中长距离就是这样&#xff0c;修为尽失&#xff0c;大概是要从头开始了&#xff0c;不过还是要乐观的面对&#xff0c;CHEER UP&#xff01; 翻看咕咚软件&#xff0c;以前的PB是21&#xff1a;12&#xff0c;在2017年9月…

Flask 项目结构

前面我们了解了 Flask 框架的特性和一些用法&#xff0c;比如创建一个简单应用、做些页面&#xff0c;以及增加鉴权模块等&#xff0c;如果要将 Flask 用于实际项目开发&#xff0c;还需要了解一下 Flask 项目结构。 Flask 是一个轻量级的 Web 框架&#xff0c;扩展性强&#…

C# Winfrom通过COM接口访问和控制Excel应用程序,将Excel数据导入DataGridView

1.首先要创建xlsx文件 2.在Com中添加引用 3. 添加命名空间 using ApExcel Microsoft.Office.Interop.Excel; --这样起个名字方面后面写 4.样例 //点击操作excelDataTable dt new DataTable();string fileName "D:\desktop\tmp\test.xlsx";ApExcel.Application exA…

uview ui 查看版号

版本查询2种方式 有两种方式可以查询到正在使用的uView的版本&#xff1a; // 通过console.log打印的形式 console.log(uni.$u.config.v);// 可以查阅uView的配置文件得知当前版本号&#xff0c;具体位置为&#xff1a; /uview-ui/libs/config/config.js

在 Google Colab 中微调用于命名实体识别的 BERT 模型

介绍 命名实体识别是自然语言处理(NLP)领域的一项主要任务。它用于检测文本中的实体,以便在下游任务中进一步使用,因为某些文本/单词对于给定上下文比其他文本/单词更具信息性和重要性。这就是 NER 有时被称为信息检索的原因,即从文本中提取相关关键词并将其分类为所需的类…

基于Python+djangoAI 农作物病虫害预警系统智能识别系统设计与实现(源码&教程)

1.背景 随着科技的发展&#xff0c;机器学习技术在各个领域中的应用越来越广泛。在农业领域&#xff0c;机器学习技术的应用有助于提高农作物的产量和质量&#xff0c;降低农业生产的成本。本文针对农作物健康识别问题&#xff0c;提出一种基于机器学习方法的农作健康识别系统&…

Effective C++条款11——在operator=中处理“自我赋值”(构造/析构/赋值运算)

“自我赋值”发生在对象被赋值给自己时: class Widget {}; Widget w; // ... w w; // 赋值给自己 这看起来有点愚蠢&#xff0c;但它合法&#xff0c;所以不要认定客户绝不会那么做。此外赋值动作并不总是那么可被一眼辨识出来&#xff0c;例如: a[i] a[j]; …

在SpringBoot使用MongoDB时出现的bug和解决

在springboot使用MongoDB时出现的bug和解决 在springboot整合MongoDB时,报错 在springboot整合MongoDB时,报错 INFO 67135 — [ main] org.mongodb.driver.connection : Closed connection [connectionId{localValue:2}] to 127.0.0.1:27017 because there was a socket excep…