手把手教你編寫入門級redis客戶端

Redis是開源的、基於內存的數據結構存儲系統,可用做數據庫、緩存以及消息代理方面。Redis支持許多種數據結構,並內置了豐富的諸如冗餘、腳本、事務、持久化等功能,深受業界喜好,被各類業務系統普遍使用。爲了方便使用,Redis官網推薦了針對各類編程語言的多種客戶端,支持java、c#、python、c++等主流編程語言。那麼你們會問,既然Redis客戶端已經這麼豐富了,爲何還要嘗試本身編寫客戶端?個人見解是,知己知彼,本身嘗試製做Redis客戶端,不只能夠加深對Redis的瞭解,並且能夠通曉Redis客戶端的原理,爲從此的更好地使用、乃至定製改造Redis做好充分準備。java

知識準備

要想親自開發Redis客戶端,須要如下知識:
一、網絡編程基礎
二、熟悉Redis協議
三、瞭解Redis的基本操做
另外文中的例子將會採用java編寫,所以最好有基本的java編程知識。python

面向讀者

本文面向Redis各層次使用者。c++

Redis Protocal

Redis協議被稱爲:RESP (REdis Serialization Protocol),客戶端經過TCP協議鏈接到客戶端的6379端口(默認端口)。
RESP協議是在Redis1.2中引入的,不過如今已是Redis2.0中的標準協議了。因此你應該再Redis客戶端中實現這個協議。git

RESP描述

RESP實際上是一個序列化協議,支持簡單字符串、錯誤、整數、整塊字符串和數組。數據類型依賴頭文字,分別表示以下:
簡單字符串的頭文字是「+」
錯誤的頭文字是「-」
整數的頭文字是「:」
整塊字符串的頭文字是「$」
數組的頭文字是「*」github

RESP在請求-響應模型中的用法

  • 客戶端向Redis服務器發送命令,以RESP整塊字符串數組的形式。redis

  • 服務器端根據命令的結果,選擇適宜的一種RESP類型返回數據庫

簡單字符串

簡單字符串是以半角加號開頭,後跟隨着不含回車換行的字符串,而後以回車換行結尾。
舉例以下:+OK\r\n
簡單字符串是非二進制安全的,若是須要二進制安全,可以使用「整塊字符串」。編程

錯誤

錯誤和簡單字符串相似,但頭文字換成半角減號了。後面跟隨的文字,能夠視爲錯誤消息內容。
舉例以下:
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of valuec#

整數

整數與簡單字符串相似,頭文字爲半角冒號。
舉例以下:
:0\r\n
:1000\r\n數組

整塊字符串

整塊字符串能夠用來標示二進制安全的、最大512MB長度的字符串。它以$符號開頭,後跟隨實際字符串長度,以回車換行結尾,後跟隨實際字符串,再最終以回車換行結尾。
舉例以下:
$6\r\nfoobar\r\n
空字符串表現形式以下:$0\r\n\r\n
nil表現形式以下:$-1\r\n\r\n

數組

數組以半角星號開頭,後接數組中元素個數,而後以回車換行結尾,而後後接各個元素。
舉例以下:
空數組:*0\r\n
包含兩個整塊字符串的數組:*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
包含三個整數的數組:*3\r\n:1\r\n:2\r\n:3\r\n
數組還支持嵌套。

Redis客戶端原理

要實現和Redis服務端通訊,首先須要與Redis服務端創建TCP通訊鏈接,而後使用上述的RESP協議,將想要執行的Redis命令發送至服務端,並等待服務端響應,而後接收到響應結果,展現給用戶。

如下代碼實現了一個簡單的獲取info的操做。

package my_redis_client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.CharBuffer;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        //定義redis服務端默認端口
        int port = 6379;

        Socket socket = null;
        BufferedReader in = null;
        PrintWriter out = null;
        
        try {
            //建立tcp鏈接
            socket = new Socket("localhost", port);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            
            //傳送info命令
            //客戶端向Redis服務器發送命令,以RESP整塊字符串數組的形式
            out.println("*1\r\n$4\r\ninfo\r\n");
            System.out.println("Redis command wat sent successfully.");
            
            //接收服務器的回覆
            CharBuffer response = CharBuffer.allocate(1024);
            int readedLen = in.read(response);
            String responseBody = response.flip().toString();
            
            //輸出服務器的回覆
            System.out.println(responseBody);
            
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        finally {
            //最後關閉相關的流
            if (out != null){
                out.close();
                out = null;
            }
            
            if (in != null) {
                try {
                    in.close();
                }
                catch(IOException e){
                    e.printStackTrace();
                }
                
                in = null;
            }
            
            if (socket != null) {
                try {
                    socket.close();
                }
                catch(IOException e){
                    e.printStackTrace();
                }
                
                socket = null;
            }
        }
    }
}

運行後,系統將會在命令行界面輸出info的執行結果。

結尾

根據上述代碼所描述的方法,就能夠繼續擴展客戶端的功能,實現Redis各類命令了。

筆者實現

源碼請參考

https://github.com/yourcaptai...

maven中央倉庫

<dependency>
  <groupId>net.yesdata</groupId>
  <artifactId>dudu-RESP-interpreter</artifactId>
  <version>1.0.4</version>
</dependency>

maven中央倉庫地址

https://oss.sonatype.org

相關文章
相關標籤/搜索