RESP的協議規範

一、官網文檔
https://redis.io/topics/protocolhtml

http://www.redis.cn/topics/pr...java

二、協議介紹
redis協議規範(Redis Protocol specification)。redis

redis協議在如下幾點之間作出了折衷:數組

  (1)簡單的實現安全

  (2)快速地被計算機解析服務器

  (3)簡單得能夠能被人工解析網絡

  (4)網絡層,Redis在TCP端口6379上監聽到來的鏈接(本質就是socket),客戶端鏈接到來時,Redis服務器爲此建立一個TCP鏈接。在客戶端與服務器端之間傳輸的每一個Redis命令或者數據都以rn結尾。app

三、請求
Redis接收由不一樣參數組成的命令。一旦收到命令,將會馬上被處理,並回復給客戶端socket

四、新的統一請求協議
在這個統一協議裏,發送給Redis服務端的全部參數都是二進制安全的。如下是通用形式:ui

*後面數量表示存在幾個$
$後面數量表示字符串的長度
例子:

*3
$3
SET
$5
mykey
$7
myvalue

上面的命令看上去像是單引號字符串,因此能夠在查詢中看到每一個字節的準確值:

"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n"

在Redis的回覆中也使用這樣的格式。批量回復時,這種格式用於每一個參數$6rnmydatarn。 實際的統一請求協議是Redis用於返回列表項,並調用 Multi-bulk回覆。 僅僅是N個以以*rn爲前綴的不一樣批量回復,是緊隨的參數(批量回復)數目。

五、回覆
Redis用不一樣的回覆類型回覆命令。它可能從服務器發送的第一個字節開始校驗回覆類型:

  (1)用單行回覆,回覆的第一個字節將是「+」

  (2)錯誤消息,回覆的第一個字節將是「-」

  (3)整型數字,回覆的第一個字節將是「:」

  (4)批量回復,回覆的第一個字節將是「$」

  (5)多個批量回復,回覆的第一個字節將是「*」

例子:狀態回覆(或者單行回覆)

以「+」開始以「rn」結尾的單行字符串形式。例如:

"+OKrn"
客戶端庫將在「+」後面返回全部數據,正如上例中字符串「OK」同樣。

有關與其餘的操做請查看官方文檔。

六、模擬Redis服務和客戶端通信,實現RESP協議通訊
枚舉類

public enum CommandRedis {
    SET, GET, SETNX
}

實現類

package com.protocol;

import org.junit.Test;

import java.io.IOException;
import java.net.Proxy;
import java.net.Socket;

public class RedisClientByResp {

    private Socket socket;

    public RedisClientByResp() {
        try {
            socket = new Socket("localhost", 6379);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("鏈接失敗" + e.getMessage());
        }
    }

    /**
     * 設置值
     * @param key
     * @param value
     * @return
     * @throws IOException
     */
    public String set(String key, String value) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append("*3").append("\r\n");
        sb.append("$").append(CommandRedis.SET.name().length()).append("\r\n");
        sb.append(CommandRedis.SET.name()).append("\r\n");
        // 注意中文漢字。一個漢字兩個字節,長度爲2
        sb.append("$").append(key.getBytes().length).append("\r\n");
        sb.append(key).append("\r\n");
        sb.append("$").append(value.getBytes().length).append("\r\n");
        sb.append(value).append("\r\n");
        System.out.println(sb.toString());

        socket.getOutputStream().write(sb.toString().getBytes());
        byte[] b = new byte[2048];
        socket.getInputStream().read(b);
        return new String(b);
    }

    /**
     * 獲取值
     * @param key
     * @return
     * @throws Exception
     */
    public String get(String key) throws Exception {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("*2").append("\r\n");
        stringBuffer.append("$").append(CommandRedis.GET.name().length()).append("\r\n");
        stringBuffer.append(CommandRedis.GET).append("\r\n");
        stringBuffer.append("$").append(key.getBytes().length).append("\r\n");
        stringBuffer.append(key).append("\r\n");

        socket.getOutputStream().write(stringBuffer.toString().getBytes());
        byte[] b = new byte[2048];
        socket.getInputStream().read(b);
        return new String(b);
    }

    /**
     * 設置值:不會覆蓋存在的值
     * @param key
     * @param value
     * @return
     * @throws Exception
     */
    public String setnx(String key, String value) throws Exception {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("*3").append("\r\n");
        stringBuffer.append("$").append(CommandRedis.SETNX.name().length()).append("\r\n");
        stringBuffer.append(CommandRedis.SETNX.name()).append("\r\n");
        stringBuffer.append("$").append(key.getBytes().length).append("\r\n");
        stringBuffer.append(key).append("\r\n");
        stringBuffer.append("$").append(value.getBytes().length).append("\r\n");
        stringBuffer.append(value).append("\r\n");

        socket.getOutputStream().write(stringBuffer.toString().getBytes());
        byte[] b = new byte[2048];
        socket.getInputStream().read(b);
        return new String(b);
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new RedisClientByResp().set("mykey" ,"myvalue"));
        System.out.println(new RedisClientByResp().get("mykey"));
    }
}
相關文章
相關標籤/搜索