Redis原理篇(三)通信协议

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一、RESP协议

1、定义

Redis是一个cs架构的软件通信一般分两步:

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

因此客户端发送命令的格式、服务端响应结果的格式必须有一个规范这个规范就是通信协议。

而在Redis采用RESP协议:

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

2、数据类型

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

数据类型说明示例
单行字符串首字节是‘+’后面跟单行字符串以CRLF(\r\n)结尾返回OK: “+OK \r\n”
错误(Errors)首字节是‘-’同上以CRLF(\r\n)结尾“-Errors message \r\n”
数值首字节是‘:’后面跟上数字格式的字符串以CRLF(\r\n)结尾“:10 \r\n”
多行字符串首字节是‘$’表示二进制安全的字符串最大支持512MB“$5\r\nhello\r\n”
数组首字节是‘*’后面跟上数组元素个数再跟上元素元素数据类型不限见下图

在这里插入图片描述

二、模拟Redis客户端

public class Main {

    static Socket socket;
    static PrintWriter writer;
    static BufferedReader reader;

    public static void main(String[] args) {
        try {
            //1.建立连接
            String host = "127.0.0.1";
            int port = 6379;
            socket = new Socket(host, port);
            //2.获取流
            writer = new PrintWriter(socket.getOutputStream());
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
            //3、发送请求
            sendRequest("set", "name", "xiaohong");
            //4、解析响应
            Object obj = handleRepose();
            System.out.println(obj);
            //5、发送请求
            sendRequest("get", "name");
            //6、解析响应
            Object obj2 = handleRepose();
            System.out.println(obj2);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // set name allen
    private static void sendRequest(String ...args) {
        writer.println("*" + args.length);
        for (String str: args) {
            writer.println("$" + str.getBytes(StandardCharsets.UTF_8).length);
            writer.println(str);
        }
        writer.flush();
    }

    private static Object handleRepose() {
        try {
            int prefix = reader.read();
            if (prefix == '+') {
                return reader.readLine();
            } else if (prefix == '-') {
                throw new RuntimeException(reader.readLine());
            } else if (prefix == ':') {
                return Long.valueOf(reader.readLine());
            } else if (prefix == '$') {
                int len = Integer.parseInt(reader.readLine());
                if (len == -1) {
                    return null;
                }
                if (len == 0) {
                    return "";
                }
                return reader.readLine();
            } else if (prefix == '*') {
                return readBulkString();
            } else {
                throw new RuntimeException("错误格式");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    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(handleRepose());
        }
        return list;
    }

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: redis