概述
Redis是開源的、基於內存的數據結構存儲系統,可用做數據庫、緩存以及消息代理方面。Redis支持許多種數據結構,並內置了豐富的諸如冗餘、腳本、事務、持久化等功能,深受業界喜好,被各類業務系統普遍使用。爲了方便使用,Redis官網推薦了針對各類編程語言的多種客戶端,支持java、c#、python、c++等主流編程語言。那麼你們會問,既然Redis客戶端已經這麼豐富了,爲何還要嘗試本身編寫客戶端?個人見解是,知己知彼,本身嘗試製做Redis客戶端,不只能夠加深對Redis的瞭解,並且能夠通曉Redis客戶端的原理,爲從此的更好地使用、乃至定製改造Redis做好充分準備。java
知識準備
要想親自開發Redis客戶端,須要如下知識:
一、網絡編程基礎
二、熟悉Redis協議
三、瞭解Redis的基本操做
另外文中的例子將會採用java編寫,所以最好有基本的java編程知識。python
面向對象
Redis Protocal
Redis協議被稱爲:RESP (REdis Serialization Protocol),客戶端經過TCP協議鏈接到客戶端的6379端口(默認端口)。
RESP協議是在Redis1.2中引入的,不過如今已是Redis2.0中的標準協議了。因此你應該再Redis客戶端中實現這個協議。c++
RESP描述
RESP實際上是一個序列化協議,支持簡單字符串、錯誤、整數、整塊字符串和數組。數據類型依賴頭文字,分別表示以下:
簡單字符串的頭文字是「+」
錯誤的頭文字是「-」
整數的頭文字是「:」
整塊字符串的頭文字是「$」
數組的頭文字是「*」web
RESP在請求-響應模型中的用法
-客戶端向Redis服務器發送命令,命令的格式是僅以RESP整塊字符串構成的數組。。
-服務器端根據命令的結果,選擇適宜的一種RESP類型返回redis
簡單字符串
簡單字符串是以半角加號開頭,後跟隨着不含回車換行的字符串,而後以回車換行結尾。
舉例以下:+OK\r\n
簡單字符串是非二進制安全的,若是須要二進制安全,可以使用「整塊字符串」。數據庫
錯誤
錯誤和簡單字符串相似,但頭文字換成半角減號了。後面跟隨的文字,能夠視爲錯誤消息內容。
舉例以下:編程
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value
整數
整數與簡單字符串相似,頭文字爲半角冒號。
舉例以下:c#
: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的操做。
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的執行結果。
本文同步分享在 博客「xiangzhihong8」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。